1 Description

This notebook performs pair-wise comparisons of qPCR gene expression, normalized to GAPDH expression. It calculates delta Cq, delta delta Cq, and fold changes in expression. Additionally, it generates box plots (delta Cq), and bar plots (fold change expression).

2 Set variables

2.1 Set sample groups

Groups are named in the following fashion:

<life.stage>.<conditioning.treatment>.<acute.treatment>

This allows for parsing downstream.

NOTE: Below is the full set of groups for the entire experiment. For the current qPCR analysis, seed and spat do not have acute treatments; just conditioning treatments.

seed.control.ambient=c("29", "40", "55", "63", "69", "101", "119", "122", "155", "164", "187", "202", "209", "214", "233", "236", "275")
seed.control.high=c("42", "59", "60", "62", "86", "102", "140", "176", "177", "184", "192", "223", "234", "243", "244", "254", "264")
seed.treated.ambient=c("14", "48", "66", "72", "89", "115", "129", "138", "156", "182", "191", "201", "227", "239", "270", "277", "280")
seed.treated.high=c("15", "19", "24", "88", "92", "105", "111", "113", "120", "128", "161", "200", "211", "256", "257", "266", "285")
spat.control.ambient=c("11", "30", "36", "52", "77", "114", "134", "142", "144", "183", "193", "229", "230", "231", "240", "272", "287")
spat.control.high=c("27", "74", "93", "96", "97", "137", "143", "153", "168", "178", "189", "206", "262", "274", "282", "284", "289")
spat.treated.ambient=c("9", "13", "38", "46", "47", "121", "145", "151", "174", "194", "197", "198", "216", "235", "241", "252", "291")
spat.treated.high=c("6", "25", "50", "78", "124", "126", "131", "160", "163", "172", "220", "226", "242", "253", "296", "298")
juvenile.control.ambient=c("18", "57", "65", "75", "79", "104", "110", "123", "125", "171", "175", "205", "238", "273", "279", "293", "317")
juvenile.control.high=c("12", "39", "43", "49", "71", "130", "141", "146", "150", "170", "195", "297", "301", "324", "351", "355", "371")
juvenile.treated.ambient=c("1", "34", "64", "83", "98", "147", "152", "158", "162", "169", "188", "271", "295", "310", "357", "361", "381")
juvenile.treated.high=c("28", "53", "61", "73", "81", "106", "109", "139", "149", "173", "181", "213", "290", "302", "311", "364", "392")
adult.control.ambient=c("3", "5", "13*", "16", "17", "80", "87", "94", "148", "159", "179", "180", "250", "258", "268", "312", "326", "330", "334", "346", "360", "377", "379", "386")
adult.control.high=c("20", "23", "26", "32", "33", "67", "70", "90", "107", "132", "135", "157", "166", "186", "207", "215", "248", "316", "341", "344", "349", "382", "394", "395")
adult.treated.ambient=c("7", "31", "35", "37", "41", "54", "84", "100", "112", "116", "118", "133", "154", "199", "203", "204", "208", "219", "294", "318", "339", "353", "363", "378")
adult.treated.high=c("21", "22", "45", "82", "85", "91", "95", "99", "103", "108", "117", "127", "165", "185", "190", "196", "232", "237", "245", "263", "276", "306", "343", "374")

2.2 Assign groups to list

# Combine vectors into lists
# Used for adding treatment info and/or subsetting downstream

groups_list <- list(juvenile.control.ambient = juvenile.control.ambient,
                                   juvenile.control.high = juvenile.control.high,
                                   juvenile.treated.ambient = juvenile.treated.ambient,
                                   juvenile.treated.high = juvenile.treated.high,
                                   adult.control.ambient = adult.control.ambient,
                                   adult.control.high = adult.control.high,
                                   adult.treated.ambient = adult.treated.ambient,
                                   adult.treated.high = adult.treated.high,
                                   seed.control.ambient = seed.control.ambient,
                                   seed.control.high = seed.control.high,
                                   seed.treated.ambient = seed.treated.ambient,
                                   seed.treated.high = seed.treated.high,
                                   spat.control.ambient = spat.control.ambient,
                                   spat.control.high = spat.control.high,
                                   spat.treated.ambient = spat.treated.ambient,
                                   spat.treated.high = spat.treated.high)

3 Functions

3.1 Calculate delta Cq

Normalized to designated normalizing gene

calculate_delta_Cq <- function(df) {
  df <- df %>%
    group_by(Sample) %>%
    mutate(delta_Cq = Cq.Mean - Cq.Mean[Target == "GAPDH"]) %>%
    ungroup()
  
  return(df)
}

3.2 Create delta Cq boxplots

3.2.1 Lifestage comparison

# Function to create box plots for each comparison
create_boxplot_delta_Cq <- function(data, comparison, t_test_results) {
  # Extract life stages from comparison
  life_stages <- unlist(strsplit(comparison, "\\."))

  # Debugging: Print life stages
  # print(paste("Life stages for comparison:", comparison))
  # print(life_stages)

  # Filter data for the relevant life stages
  filtered_data <- data %>%
    filter(life.stage %in% life_stages)

  # Debugging: Print filtered data
  # print("Filtered data:")
  # print(filtered_data)

  # Check if both life stages are included
  if (!all(life_stages %in% unique(filtered_data$life.stage))) {
    stop("Not all life stages are included in the filtered data")
  }

  y_limits <- range(filtered_data$delta_Cq, na.rm = TRUE)

  # Debugging: Print y_limits
  # print("Y limits:")
  # print(y_limits)

  # Filter t_test_results for the current comparison
  t_test_results_filtered <- t_test_results %>%
    filter(comparison == !!comparison)

  # Debugging: Print filtered t_test_results
  # print("Filtered t_test_results:")
  # print(t_test_results_filtered)

  # Filter t_test_results for asterisks
  t_test_results_with_asterisks <- t_test_results_filtered %>%
    filter(asterisk != "")

  # Debugging: Print t_test_results_with_asterisks
  # print("t_test_results_with_asterisks:")
  # print(t_test_results_with_asterisks)

  formatted_title <- paste0(toupper(substring(life_stages[1], 1, 1)), substring(life_stages[1], 2), 
                            " vs. ", 
                            toupper(substring(life_stages[2], 1, 1)), substring(life_stages[2], 2))

  boxplot <- ggplot(filtered_data, aes(x = Target, y = delta_Cq, fill = life.stage)) +
    geom_boxplot(position = position_dodge(width = 0.75)) +
    theme_minimal() +
    theme(legend.position = "right") +
    scale_fill_manual(values=c("darkgray", "salmon", "lightblue", "lightgreen")) +
    ylim(y_limits) +
    labs(x = "Target", y = "Delta Cq", title = formatted_title) +
    # Highlighted section: Adds asterisks
    geom_text(data = t_test_results_with_asterisks, 
              aes(x = Target, y = y_limits[2] - 1, label = asterisk), 
              vjust = -0.5, size = 8, color = "black", inherit.aes = FALSE)

  print(boxplot)
}

3.2.2 Conditioning comparisons

  1. Extract Life Stage and Conditioning Treatments:
  • The comparison string is split into its components (life_stage, treatment1, and treatment2).
  1. Filter Data:
  • The filtered_data data frame is filtered to include only the rows with the relevant life stage and conditioning treatments.
  1. Check for Both Treatments:
  • Ensure that both treatments are included in the filtered_data.
  1. Filter T-Test Results:
  • The t_test_results_filtered data frame is filtered for the specific comparison.

  • The t_test_results_with_asterisks data frame is created to include only the rows with asterisks.

  1. Format the Title:
  • The formatted_title variable is created by capitalizing the first letter of each component and concatenating them with ” - ” and ” vs. ” in between.

  • This should create box plots comparing conditioning treatments within each life stage, with titles formatted as <life.stage> - Treated vs. Control.

# Function to create box plots for each comparison of conditioning treatments within life stages
create_boxplot_conditioning <- function(data, comparison, t_test_results) {
  # Extract life stage and conditioning treatments from comparison
  comparison_parts <- unlist(strsplit(comparison, "\\."))
  life_stage <- comparison_parts[1]
  treatment1 <- comparison_parts[2]
  treatment2 <- comparison_parts[3]

  # Debugging: Print life stage and treatments
  # print(paste("Life stage and treatments for comparison:", comparison))
  # print(c(life_stage, treatment1, treatment2))

  # Filter data for the relevant life stage and conditioning treatments
  filtered_data <- data %>%
    filter(life.stage == life_stage, conditioning.treatment %in% c(treatment1, treatment2))

  # Debugging: Print filtered data
  # print("Filtered data:")
  # print(filtered_data)

  # Check if both treatments are included
  if (!all(c(treatment1, treatment2) %in% unique(filtered_data$conditioning.treatment))) {
    stop("Not all treatments are included in the filtered data")
  }

  y_limits <- range(filtered_data$delta_Cq, na.rm = TRUE)

  # Debugging: Print y_limits
  # print("Y limits:")
  # print(y_limits)

  # Filter t_test_results for the current comparison
  t_test_results_filtered <- t_test_results %>%
    filter(comparison == !!comparison)

  # Debugging: Print filtered t_test_results
  # print("Filtered t_test_results:")
  # print(t_test_results_filtered)

  # Filter t_test_results for asterisks
  t_test_results_with_asterisks <- t_test_results_filtered %>%
    filter(asterisk != "")

  # Debugging: Print t_test_results_with_asterisks
  # print("t_test_results_with_asterisks:")
  # print(t_test_results_with_asterisks)

  # Format the title
  formatted_title <- paste0(toupper(substring(life_stage, 1, 1)), substring(life_stage, 2), 
                            " - ", 
                            toupper(substring(treatment1, 1, 1)), substring(treatment1, 2), 
                            " vs. ", 
                            toupper(substring(treatment2, 1, 1)), substring(treatment2, 2))

  boxplot <- ggplot(filtered_data, aes(x = Target, y = delta_Cq, fill = conditioning.treatment)) +
    geom_boxplot(position = position_dodge(width = 0.75)) +
    theme_minimal() +
    theme(legend.position = "right") +
    scale_fill_manual(values=c("darkgray", "salmon")) +
    ylim(y_limits) +
    labs(x = "Target", y = "Delta Cq", title = formatted_title) +
    # Highlighted section: Adds asterisks
    geom_text(data = t_test_results_with_asterisks, 
              aes(x = Target, y = y_limits[2] - 1, label = asterisk), 
              vjust = -0.5, size = 8, color = "black", inherit.aes = FALSE)

  print(boxplot)
}

3.2.3 Acute comparisons

  1. Extract Life Stage and Acute Treatments:
  • The comparison string is split into its components (life_stage, treatment1, and treatment2).
  1. Filter Data:
  • The filtered_data data frame is filtered to include only the rows with the relevant life stage and acute treatments.
  1. Check for Both Treatments:
  • Ensure that both treatments are included in the filtered_data.
  1. Filter T-Test Results:
  • The t_test_results_filtered data frame is filtered for the specific comparison.

  • The t_test_results_with_asterisks data frame is created to include only the rows with asterisks. Format the Title:

  1. The formatted_title variable is created by capitalizing the first letter of each component and concatenating them with ” - ” and ” vs. ” in between.
  • This should create box plots comparing acute treatments within each life stage, with titles formatted as <life.stage> - Ambient vs. High.
# Function to create box plots for each comparison of acute treatments within life stages
create_boxplot_acute <- function(data, comparison, t_test_results) {
  # Extract life stage and acute treatments from comparison
  comparison_parts <- unlist(strsplit(comparison, "\\."))
  life_stage <- comparison_parts[1]
  treatment1 <- comparison_parts[2]
  treatment2 <- comparison_parts[3]

  # Debugging: Print life stage and treatments
  # print(paste("Life stage and treatments for comparison:", comparison))
  # print(c(life_stage, treatment1, treatment2))

  # Filter data for the relevant life stage and acute treatments
  filtered_data <- data %>%
    filter(life.stage == life_stage, acute.treatment %in% c(treatment1, treatment2))

  # Debugging: Print filtered data
  # print("Filtered data:")
  # print(filtered_data)

  # Check if both treatments are included
  if (!all(c(treatment1, treatment2) %in% unique(filtered_data$acute.treatment))) {
    stop("Not all treatments are included in the filtered data")
  }

  y_limits <- range(filtered_data$delta_Cq, na.rm = TRUE)

  # Debugging: Print y_limits
  # print("Y limits:")
  # print(y_limits)

  # Filter t_test_results for the current comparison
  t_test_results_filtered <- t_test_results %>%
    filter(comparison == !!comparison)

  # Debugging: Print filtered t_test_results
  # print("Filtered t_test_results:")
  # print(t_test_results_filtered)

  # Filter t_test_results for asterisks
  t_test_results_with_asterisks <- t_test_results_filtered %>%
    filter(asterisk != "")

  # Debugging: Print t_test_results_with_asterisks
  # print("t_test_results_with_asterisks:")
  # print(t_test_results_with_asterisks)

  # Format the title
  formatted_title <- paste0(toupper(substring(life_stage, 1, 1)), substring(life_stage, 2), 
                            " - ", 
                            toupper(substring(treatment1, 1, 1)), substring(treatment1, 2), 
                            " vs. ", 
                            toupper(substring(treatment2, 1, 1)), substring(treatment2, 2))

  boxplot <- ggplot(filtered_data, aes(x = Target, y = delta_Cq, fill = acute.treatment)) +
    geom_boxplot(position = position_dodge(width = 0.75)) +
    theme_minimal() +
    theme(legend.position = "right") +
    scale_fill_manual(values=c("darkgray", "salmon")) +
    ylim(y_limits) +
    labs(x = "Target", y = "Delta Cq", title = formatted_title) +
    # Highlighted section: Adds asterisks
    geom_text(data = t_test_results_with_asterisks, 
              aes(x = Target, y = y_limits[2] - 1, label = asterisk), 
              vjust = -0.5, size = 8, color = "magenta", inherit.aes = FALSE)

  print(boxplot)
}

3.2.4 Acute treatements within life stage conditioning

# Function to create box plots for each comparison of acute treatments within life stages and conditioning treatments
create_boxplot_acute_conditioning <- function(data, comparison, t_test_results) {
  # Extract life stage, conditioning treatment, and acute treatments from comparison
  comparison_parts <- unlist(strsplit(comparison, "\\."))
  life_stage <- comparison_parts[1]
  conditioning_treatment <- comparison_parts[2]
  treatment1 <- comparison_parts[3]
  treatment2 <- comparison_parts[5]

  # Filter data for the relevant life stage, conditioning treatment, and acute treatments
  filtered_data <- data %>%
    filter(life.stage == life_stage, conditioning.treatment == conditioning_treatment, acute.treatment %in% c(treatment1, treatment2))

  # Check if both treatments are included
  if (!all(c(treatment1, treatment2) %in% unique(filtered_data$acute.treatment))) {
    stop("Not all treatments are included in the filtered data")
  }

  y_limits <- range(filtered_data$delta_Cq, na.rm = TRUE)

  # Filter t_test_results for the current comparison
  t_test_results_filtered <- t_test_results %>%
    filter(comparison == !!comparison)

  # Filter t_test_results for asterisks
  t_test_results_with_asterisks <- t_test_results_filtered %>%
    filter(asterisk != "")

  # Format the title
  formatted_title <- paste0(toupper(substring(life_stage, 1, 1)), substring(life_stage, 2), 
                            " - ", 
                            toupper(substring(conditioning_treatment, 1, 1)), substring(conditioning_treatment, 2), 
                            " - ", 
                            toupper(substring(treatment1, 1, 1)), substring(treatment1, 2), 
                            " vs. ", 
                            toupper(substring(treatment2, 1, 1)), substring(treatment2, 2))

  boxplot <- ggplot(filtered_data, aes(x = Target, y = delta_Cq, fill = acute.treatment)) +
    geom_boxplot(position = position_dodge(width = 0.75)) +
    theme_minimal() +
    theme(legend.position = "right") +
    scale_fill_manual(values=c("darkgray", "salmon")) +
    ylim(y_limits) +
    labs(x = "Target", y = "Delta Cq", title = formatted_title) +
    # Adds asterisks
    geom_text(data = t_test_results_with_asterisks, 
              aes(x = Target, y = y_limits[2] - 1, label = asterisk), 
              vjust = -0.5, size = 8, color = "black", inherit.aes = FALSE)

  print(boxplot)
}

4 Read in files

# Get a list of all CSV files in the directory with the naming structure "*Cq-Results.csv"
cq_file_list <- list() # Initialize list
cq_file_list <- list.files(path = cqs_directory, pattern = "Cq-Results\\.csv$", full.names = TRUE)

# Initialize an empty list to store the data frames
data_frames_list <- list()

# Loop through each file and read it into a data frame, then add it to the list
for (file in cq_file_list) {
  data <- read.csv(file, header = TRUE)
  data$Sample <- as.character(data$Sample)  # Convert Sample column to character type
  data_frames_list[[file]] <- data
}

# Combine all data frames into a single data frame
combined_df <- bind_rows(data_frames_list, .id = "data_frame_id")

str(combined_df)
'data.frame':   2192 obs. of  17 variables:
 $ data_frame_id         : chr  "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" ...
 $ X                     : logi  NA NA NA NA NA NA ...
 $ Well                  : chr  "A01" "A02" "A03" "A04" ...
 $ Fluor                 : chr  "SYBR" "SYBR" "SYBR" "SYBR" ...
 $ Target                : chr  "ATPsynthase" "ATPsynthase" "ATPsynthase" "ATPsynthase" ...
 $ Content               : chr  "Unkn-01" "Unkn-01" "Unkn-02" "Unkn-02" ...
 $ Sample                : chr  "206" "206" "220" "220" ...
 $ Biological.Set.Name   : logi  NA NA NA NA NA NA ...
 $ Cq                    : num  26.7 26.7 25.8 25.9 25.1 ...
 $ Cq.Mean               : num  26.7 26.7 25.9 25.9 25.1 ...
 $ Cq.Std..Dev           : num  0.0455 0.0455 0.0239 0.0239 0.0813 ...
 $ Starting.Quantity..SQ.: num  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ Log.Starting.Quantity : num  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ SQ.Mean               : num  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ SQ.Std..Dev           : num  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ Set.Point             : int  60 60 60 60 60 60 60 60 60 60 ...
 $ Well.Note             : logi  NA NA NA NA NA NA ...

5 Clean data

5.1 Replace target names

# Remove rows with Sample name "NTC"
combined_df <- combined_df[combined_df$Sample != "NTC", ]


# Replace values in the Target column
combined_df$Target <- gsub("Cg_GAPDH_205_F-355_R \\(SR IDs: 1172/3\\)", "GAPDH", combined_df$Target)

combined_df$Target <- gsub("Cg_ATPsynthase_F/R \\(SR IDs: 1385/6\\)", "ATPsynthase", combined_df$Target)

combined_df$Target <- gsub("Cg_cGAS \\(SR IDs: 1826/7\\)", "cGAS", combined_df$Target)

combined_df$Target <- gsub("Cg_citrate_synthase \\(SR IDs: 1383/4\\)", "citrate synthase", combined_df$Target)

combined_df$Target <- gsub("Cg_DNMT1_F \\(SR IDs: 1510/1\\)", "DNMT1", combined_df$Target)

combined_df$Target <- gsub("Cg_HSP70_F/R \\(SR IDs: 598/9\\)", "HSP70", combined_df$Target)

combined_df$Target <- gsub("Cg_Hsp90_F/R \\(SR IDs: 1532/3\\)", "HSP90", combined_df$Target)

combined_df$Target <- gsub("Cg_VIPERIN_F/R \\(SR IDs: 1828/9\\)", "viperin", combined_df$Target)

str(combined_df)
'data.frame':   2180 obs. of  17 variables:
 $ data_frame_id         : chr  "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" ...
 $ X                     : logi  NA NA NA NA NA NA ...
 $ Well                  : chr  "A01" "A02" "A03" "A04" ...
 $ Fluor                 : chr  "SYBR" "SYBR" "SYBR" "SYBR" ...
 $ Target                : chr  "ATPsynthase" "ATPsynthase" "ATPsynthase" "ATPsynthase" ...
 $ Content               : chr  "Unkn-01" "Unkn-01" "Unkn-02" "Unkn-02" ...
 $ Sample                : chr  "206" "206" "220" "220" ...
 $ Biological.Set.Name   : logi  NA NA NA NA NA NA ...
 $ Cq                    : num  26.7 26.7 25.8 25.9 25.1 ...
 $ Cq.Mean               : num  26.7 26.7 25.9 25.9 25.1 ...
 $ Cq.Std..Dev           : num  0.0455 0.0455 0.0239 0.0239 0.0813 ...
 $ Starting.Quantity..SQ.: num  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ Log.Starting.Quantity : num  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ SQ.Mean               : num  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ SQ.Std..Dev           : num  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ Set.Point             : int  60 60 60 60 60 60 60 60 60 60 ...
 $ Well.Note             : logi  NA NA NA NA NA NA ...
levels(as.factor(combined_df$Target))
[1] "ATPsynthase"      "cGAS"             "citrate synthase" "DNMT1"           
[5] "GAPDH"            "HSP70"            "HSP90"            "viperin"         

5.2 Identify Samples with Cq.Std..Dev > 0.5

# Filter out rows where Cq.Std..Dev is NA
combined_df <- combined_df[!is.na(combined_df$Cq.Std..Dev), ]

# Filter rows where Cq.Std..Dev is greater than 0.5
high_cq_std_dev <- combined_df[combined_df$Cq.Std..Dev > 0.5, ]

# Print the filtered rows with specified columns, without row names
print(high_cq_std_dev[, c("Target", "Sample", "Cq", "Cq.Std..Dev")], row.names = FALSE)
           Target Sample       Cq Cq.Std..Dev
            HSP70    244 33.10339   4.0838809
            HSP70    244 27.32791   4.0838809
            HSP90    223 24.85319   0.7548714
            HSP90    223 25.92074   0.7548714
          viperin    223 30.30089   0.6058663
          viperin    223 31.15772   0.6058663
          viperin    243 32.57817   0.5527617
          viperin    243 33.35989   0.5527617
            DNMT1    296 31.21374   0.6417578
            DNMT1    296 30.30616   0.6417578
            DNMT1    298 35.68716   0.5406704
            DNMT1    298 34.92253   0.5406704
            DNMT1    223 32.24089   0.6214201
            DNMT1    223 33.11971   0.6214201
            DNMT1    243 36.63921   0.5125743
            DNMT1    243 35.91432   0.5125743
            DNMT1    285 33.63443   0.7036122
            DNMT1    285 34.62949   0.7036122
            GAPDH    316 23.94926   8.5684728
            GAPDH    316 24.14183   8.5684728
            GAPDH    316 38.88564   8.5684728
            GAPDH    213 26.98012   2.2910353
            GAPDH    213 23.00009   2.2910353
            GAPDH    213 26.95634   2.2910353
            GAPDH    263 22.42154   0.8731474
            GAPDH    263 23.77008   0.8731474
            GAPDH    263 24.05667   0.8731474
 citrate synthase    230 24.44066   4.4783429
 citrate synthase    230 24.40421   4.4783429
 citrate synthase    230 32.17909   4.4783429
          viperin    227 30.47773   3.5152533
          viperin    227 30.37738   3.5152533
          viperin    227 36.51553   3.5152533
          viperin    245 26.05748   5.1635899
          viperin    245 34.98192   5.1635899
          viperin    245 26.01928   5.1635899
          viperin    341 26.48675   2.9838590
          viperin    341 31.67235   2.9838590
          viperin    341 26.52174   2.9838590
          viperin    344 29.98184   2.3712440
          viperin    344 25.90358   2.3712440
          viperin    344 25.84648   2.3712440
          viperin    355 28.79712   0.5821437
          viperin    355 29.57428   0.5821437
          viperin    355 28.43490   0.5821437

5.3 Remove bad technical reps

# Group by Sample and Target, then filter out the outlier replicate
combined.fitered_df<- combined_df %>%
  group_by(Sample, Target) %>%
  filter(abs(Cq - mean(Cq, na.rm = TRUE)) <= Cq.Std..Dev)

# Print the filtered data frame
str(combined.fitered_df)
gropd_df [1,520 × 17] (S3: grouped_df/tbl_df/tbl/data.frame)
 $ data_frame_id         : chr [1:1520] "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" "lifestage_carryover/data/qPCR/Cq/sam_2024-03-25_06-10-54_Connect-Quantification-Cq-Results.csv" ...
 $ X                     : logi [1:1520] NA NA NA NA NA NA ...
 $ Well                  : chr [1:1520] "A01" "A02" "A03" "A04" ...
 $ Fluor                 : chr [1:1520] "SYBR" "SYBR" "SYBR" "SYBR" ...
 $ Target                : chr [1:1520] "ATPsynthase" "ATPsynthase" "ATPsynthase" "ATPsynthase" ...
 $ Content               : chr [1:1520] "Unkn-01" "Unkn-01" "Unkn-02" "Unkn-02" ...
 $ Sample                : chr [1:1520] "206" "206" "220" "220" ...
 $ Biological.Set.Name   : logi [1:1520] NA NA NA NA NA NA ...
 $ Cq                    : num [1:1520] 26.7 26.7 25.8 25.9 25.1 ...
 $ Cq.Mean               : num [1:1520] 26.7 26.7 25.9 25.9 25.1 ...
 $ Cq.Std..Dev           : num [1:1520] 0.0455 0.0455 0.0239 0.0239 0.0813 ...
 $ Starting.Quantity..SQ.: num [1:1520] NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ Log.Starting.Quantity : num [1:1520] NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ SQ.Mean               : num [1:1520] NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ SQ.Std..Dev           : num [1:1520] NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
 $ Set.Point             : int [1:1520] 60 60 60 60 60 60 60 60 60 60 ...
 $ Well.Note             : logi [1:1520] NA NA NA NA NA NA ...
 - attr(*, "groups")= tibble [760 × 3] (S3: tbl_df/tbl/data.frame)
  ..$ Sample: chr [1:760] "200" "200" "200" "200" ...
  ..$ Target: chr [1:760] "ATPsynthase" "DNMT1" "GAPDH" "HSP70" ...
  ..$ .rows : list<int> [1:760] 
  .. ..$ : int [1:2] 21 22
  .. ..$ : int [1:2] 245 246
  .. ..$ : int [1:2] 85 86
  .. ..$ : int [1:2] 53 54
  .. ..$ : int [1:2] 117 118
  .. ..$ : int [1:2] 149 150
  .. ..$ : int [1:2] 213 214
  .. ..$ : int [1:2] 181 182
  .. ..$ : int [1:2] 321 322
  .. ..$ : int [1:2] 889 890
  .. ..$ : int [1:2] 637 638
  .. ..$ : int [1:2] 1047 1048
  .. ..$ : int [1:2] 1205 1206
  .. ..$ : int [1:2] 479 480
  .. ..$ : int [1:2] 731 732
  .. ..$ : int [1:2] 1363 1364
  .. ..$ : int [1:2] 323 324
  .. ..$ : int [1:2] 891 892
  .. ..$ : int [1:2] 639 640
  .. ..$ : int [1:2] 1049 1050
  .. ..$ : int [1:2] 1207 1208
  .. ..$ : int [1:2] 481 482
  .. ..$ : int [1:2] 733 734
  .. ..$ : int [1:2] 1365 1366
  .. ..$ : int [1:2] 325 326
  .. ..$ : int [1:2] 893 894
  .. ..$ : int [1:2] 641 642
  .. ..$ : int [1:2] 1051 1052
  .. ..$ : int [1:2] 1209 1210
  .. ..$ : int [1:2] 483 484
  .. ..$ : int [1:2] 735 736
  .. ..$ : int [1:2] 1367 1368
  .. ..$ : int [1:2] 327 328
  .. ..$ : int [1:2] 895 896
  .. ..$ : int [1:2] 643 644
  .. ..$ : int [1:2] 1053 1054
  .. ..$ : int [1:2] 1211 1212
  .. ..$ : int [1:2] 485 486
  .. ..$ : int [1:2] 737 738
  .. ..$ : int [1:2] 1369 1370
  .. ..$ : int [1:2] 329 330
  .. ..$ : int [1:2] 897 898
  .. ..$ : int [1:2] 645 646
  .. ..$ : int [1:2] 1055 1056
  .. ..$ : int [1:2] 1213 1214
  .. ..$ : int [1:2] 487 488
  .. ..$ : int [1:2] 739 740
  .. ..$ : int [1:2] 1371 1372
  .. ..$ : int [1:2] 1 2
  .. ..$ : int [1:2] 225 226
  .. ..$ : int [1:2] 65 66
  .. ..$ : int [1:2] 33 34
  .. ..$ : int [1:2] 97 98
  .. ..$ : int [1:2] 129 130
  .. ..$ : int [1:2] 193 194
  .. ..$ : int [1:2] 161 162
  .. ..$ : int [1:2] 331 332
  .. ..$ : int [1:2] 899 900
  .. ..$ : int [1:2] 647 648
  .. ..$ : int [1:2] 1057 1058
  .. ..$ : int [1:2] 1215 1216
  .. ..$ : int [1:2] 489 490
  .. ..$ : int [1:2] 741 742
  .. ..$ : int [1:2] 1373 1374
  .. ..$ : int [1:2] 333 334
  .. ..$ : int [1:2] 901 902
  .. ..$ : int [1:2] 649 650
  .. ..$ : int [1:2] 1059 1060
  .. ..$ : int [1:2] 1217 1218
  .. ..$ : int [1:2] 491 492
  .. ..$ : int [1:2] 743 744
  .. ..$ : int [1:2] 1375 1376
  .. ..$ : int [1:2] 335 336
  .. ..$ : int [1:2] 903 904
  .. ..$ : int [1:2] 651 652
  .. ..$ : int [1:2] 1061 1062
  .. ..$ : int [1:2] 1219 1220
  .. ..$ : int [1:2] 493 494
  .. ..$ : int [1:2] 745 746
  .. ..$ : int [1:2] 1377 1378
  .. ..$ : int [1:2] 337 338
  .. ..$ : int [1:2] 905 906
  .. ..$ : int [1:2] 653 654
  .. ..$ : int [1:2] 1063 1064
  .. ..$ : int [1:2] 1221 1222
  .. ..$ : int [1:2] 495 496
  .. ..$ : int [1:2] 747 748
  .. ..$ : int [1:2] 1379 1380
  .. ..$ : int [1:2] 339 340
  .. ..$ : int [1:2] 907 908
  .. ..$ : int [1:2] 655 656
  .. ..$ : int [1:2] 1065 1066
  .. ..$ : int [1:2] 1223 1224
  .. ..$ : int [1:2] 497 498
  .. ..$ : int [1:2] 749 750
  .. ..$ : int [1:2] 1381 1382
  .. ..$ : int [1:2] 341 342
  .. ..$ : int [1:2] 909 910
  .. ..$ : int [1:2] 657 658
  .. .. [list output truncated]
  .. ..@ ptype: int(0) 
  ..- attr(*, ".drop")= logi TRUE

6 Group samples by target

# Group by Sample and Target, then summarize to get unique rows for each sample
grouped_df <- combined.fitered_df%>%
  group_by(Sample, Target) %>%
  summarize(Cq.Mean = mean(Cq, na.rm = TRUE)) %>%
  ungroup()

str(grouped_df)
tibble [760 × 3] (S3: tbl_df/tbl/data.frame)
 $ Sample : chr [1:760] "200" "200" "200" "200" ...
 $ Target : chr [1:760] "ATPsynthase" "DNMT1" "GAPDH" "HSP70" ...
 $ Cq.Mean: num [1:760] 25.2 33.6 25.4 31.8 26 ...

7 Add life stage and treatment cols

# Initialize new columns
grouped_df <- grouped_df %>%
  mutate(life.stage = NA_character_,
         conditioning.treatment = NA_character_,
         acute.treatment = NA_character_)

# Loop through each vector
for (vec_name in names(groups_list)) {
  vec <- groups_list[[vec_name]]
  stage <- strsplit(vec_name, "\\.")[[1]][1]
  conditioning_treatment <- strsplit(vec_name, "\\.")[[1]][2]
  acute_treatment <- strsplit(vec_name, "\\.")[[1]][3]
  
  # Loop through each row in grouped_df
  for (i in 1:nrow(grouped_df)) {
    sample <- grouped_df$Sample[i]
    
    # Check if sample is in the vector
    if (sample %in% vec) {
      # Update life.stage and treatment columns
      grouped_df$life.stage[i] <- stage
      grouped_df$conditioning.treatment[i] <- conditioning_treatment
      grouped_df$acute.treatment[i] <-acute_treatment
    }
  }
}

str(grouped_df)
tibble [760 × 6] (S3: tbl_df/tbl/data.frame)
 $ Sample                : chr [1:760] "200" "200" "200" "200" ...
 $ Target                : chr [1:760] "ATPsynthase" "DNMT1" "GAPDH" "HSP70" ...
 $ Cq.Mean               : num [1:760] 25.2 33.6 25.4 31.8 26 ...
 $ life.stage            : chr [1:760] "seed" "seed" "seed" "seed" ...
 $ conditioning.treatment: chr [1:760] "treated" "treated" "treated" "treated" ...
 $ acute.treatment       : chr [1:760] "high" "high" "high" "high" ...

8 Delta Cq to Normalizing Gene

# Calculate delta Cq by subtracting GAPDH Cq.Mean from each corresponding Sample Cq.Mean
delta_Cq_df <- calculate_delta_Cq(grouped_df)

# Filters out normalizing gene, since no need to compare normalizing gene to itself.
delta_Cq_df <- delta_Cq_df %>%
  filter(!is.na(life.stage), !is.na(Target), Target != "GAPDH")

str(delta_Cq_df)
tibble [665 × 7] (S3: tbl_df/tbl/data.frame)
 $ Sample                : chr [1:665] "200" "200" "200" "200" ...
 $ Target                : chr [1:665] "ATPsynthase" "DNMT1" "HSP70" "HSP90" ...
 $ Cq.Mean               : num [1:665] 25.2 33.6 31.8 26 30.6 ...
 $ life.stage            : chr [1:665] "seed" "seed" "seed" "seed" ...
 $ conditioning.treatment: chr [1:665] "treated" "treated" "treated" "treated" ...
 $ acute.treatment       : chr [1:665] "high" "high" "high" "high" ...
 $ delta_Cq              : num [1:665] -0.243 8.168 6.349 0.578 5.135 ...

8.1 t-tests

8.1.1 Life Stages

This code does the following:

  1. Extracts the unique life.stage levels from the data frame.
  2. Generates all possible pairs of life.stage levels using the combn function.
  3. Iterates over each pair and performs the t-test for each Target. Adds an asterisk column and an asterisk if the p-value is <= 0.05. Useful for downstream parsing.
  4. Stores the results in a list and combines them into a single data frame.
  5. Adds a comparison column to indicate which life.stage levels were compared.
# Extract unique life.stage levels
unique_life_stages <- unique(delta_Cq_df$life.stage)

# Generate all possible pairs of life.stage levels
life_stage_pairs <- combn(unique_life_stages, 2, simplify = FALSE)

# Initialize a list to store results
life_stage_t_test_results_list <- list()

for (pair in life_stage_pairs) {
  stage1 <- pair[1]
  stage2 <- pair[2]
  
  # Perform t-test for each Target comparing the two life.stage levels
  t_test_results <- delta_Cq_df %>%
    filter(life.stage %in% c(stage1, stage2)) %>%
    group_by(Target) %>%
    summarise(
      t_test_result = list(t.test(delta_Cq ~ life.stage))
    ) %>%
    ungroup() %>%
    mutate(
      estimate_diff = sapply(t_test_result, function(x) x$estimate[1] - x$estimate[2]),
      p_value = sapply(t_test_result, function(x) x$p.value),
      asterisk = ifelse(p_value <= 0.05, "*", ""), # Adds asterisk column and asterisk for p-value.
      comparison = paste(stage1, "vs", stage2, sep = ".")
    ) %>%
    select(!t_test_result)
  
  life_stage_t_test_results_list[[paste(stage1, stage2, sep = ".")]] <- t_test_results
}

# Combine results into a single data frame
life_stage_t_test_results_df <- bind_rows(life_stage_t_test_results_list, .id = "comparison")

# View the results
print(life_stage_t_test_results_df)
# A tibble: 42 × 5
   Target           estimate_diff   p_value asterisk comparison   
   <chr>                    <dbl>     <dbl> <chr>    <chr>        
 1 ATPsynthase             0.310  0.0183    "*"      seed.adult   
 2 DNMT1                  -0.0736 0.829     ""       seed.adult   
 3 HSP70                   0.179  0.702     ""       seed.adult   
 4 HSP90                   0.727  0.00635   "*"      seed.adult   
 5 cGAS                   -0.0136 0.963     ""       seed.adult   
 6 citrate synthase       -0.215  0.391     ""       seed.adult   
 7 viperin                -1.08   0.0000737 "*"      seed.adult   
 8 ATPsynthase             0.207  0.0819    ""       seed.juvenile
 9 DNMT1                  -0.434  0.254     ""       seed.juvenile
10 HSP70                   0.657  0.179     ""       seed.juvenile
# ℹ 32 more rows

8.1.2 Conditioning treatments

This code does the following:

  1. Extracts the unique life.stage levels from the data frame.
  2. For each life.stage, extracts the unique conditioning.treatment levels.
  3. Generates all possible pairs of conditioning.treatment levels within each life.stage.
  4. Iterates over each pair and performs the t-test for each Target. Adds an asterisk column and an asterisk if the p-value is <= 0.05. Useful for downstream parsing.
  5. Stores the results in a list and combines them into a single data frame.
  6. Adds a comparison column to indicate which life.stage and conditioning.treatment levels were compared.
# Extract unique life.stage levels
unique_life_stages <- unique(delta_Cq_df$life.stage)

# Initialize a list to store results
conditioning_treatment_t_test_results_list <- list()

for (stage in unique_life_stages) {
  # Extract unique conditioning.treatment levels within the current life.stage
  unique_treatments <- unique(delta_Cq_df %>% filter(life.stage == stage) %>% pull(conditioning.treatment))
  
  # Generate all possible pairs of conditioning.treatment levels
  treatment_pairs <- combn(unique_treatments, 2, simplify = FALSE)
  
  for (pair in treatment_pairs) {
    treatment1 <- pair[1]
    treatment2 <- pair[2]
    
    # Perform t-test for each Target comparing the two conditioning.treatment levels within the current life.stage
    t_test_results <- delta_Cq_df %>%
      filter(life.stage == stage, conditioning.treatment %in% c(treatment1, treatment2)) %>%
      group_by(Target) %>%
      summarise(
        t_test_result = list(t.test(delta_Cq ~ conditioning.treatment))
      ) %>%
      ungroup() %>%
      mutate(
        estimate_diff = sapply(t_test_result, function(x) x$estimate[1] - x$estimate[2]),
        p_value = sapply(t_test_result, function(x) x$p.value),
        asterisk = ifelse(p_value <= 0.05, "*", ""), # Adds asterisk column and asterisk for p-value.
        comparison = paste(stage, treatment1, "vs", treatment2, sep = ".")
      ) %>%
      select(!t_test_result)
    
    conditioning_treatment_t_test_results_list[[paste(stage, treatment1, treatment2, sep = ".")]] <- t_test_results
  }
}

# Combine results into a single data frame
conditioning_treatment_t_test_results_df <- bind_rows(conditioning_treatment_t_test_results_list, .id = "comparison")

# View the results
print(conditioning_treatment_t_test_results_df)
# A tibble: 28 × 5
   Target           estimate_diff p_value asterisk comparison           
   <chr>                    <dbl>   <dbl> <chr>    <chr>                
 1 ATPsynthase            -0.0248   0.907 ""       seed.treated.control 
 2 DNMT1                   0.206    0.746 ""       seed.treated.control 
 3 HSP70                  -0.123    0.851 ""       seed.treated.control 
 4 HSP90                  -0.299    0.439 ""       seed.treated.control 
 5 cGAS                   -0.0776   0.888 ""       seed.treated.control 
 6 citrate synthase       -0.0148   0.976 ""       seed.treated.control 
 7 viperin                 0.160    0.695 ""       seed.treated.control 
 8 ATPsynthase             0.0779   0.603 ""       adult.treated.control
 9 DNMT1                   0.312    0.278 ""       adult.treated.control
10 HSP70                  -0.941    0.177 ""       adult.treated.control
# ℹ 18 more rows

8.1.3 Acute treatments

This code does the following:

  1. Extracts the unique life.stage levels from the data frame.
  2. For each life.stage, extracts the unique acute.treatment levels.
  3. Generates all possible pairs of acute.treatment levels within each life.stage.
  4. Iterates over each pair and performs the t-test for each Target. Adds an asterisk column and an asterisk if the p-value is <= 0.05. Useful for downstream parsing.
  5. Stores the results in a list and combines them into a single data frame.
  6. Adds a comparison column to indicate which life.stage and acute.treatment levels were compared.

Excludes seed and spat, as these were only held at ambient for the acute treatment.

# Extract unique life.stage levels, excluding 'seed' and 'spat'
unique_life_stages <- unique(delta_Cq_df$life.stage)
unique_life_stages <- setdiff(unique_life_stages, c("seed", "spat"))

# Initialize a list to store results
acute_treatment_t_test_results_list <- list()

for (stage in unique_life_stages) {
  # Extract unique acute.treatment levels within the current life.stage
  unique_treatments <- unique(delta_Cq_df %>% filter(life.stage == stage) %>% pull(acute.treatment))
  
  # Check if there are at least 2 unique treatments
  if (length(unique_treatments) >= 2) {
    # Generate all possible pairs of acute.treatment levels
    treatment_pairs <- combn(unique_treatments, 2, simplify = FALSE)
    
    for (pair in treatment_pairs) {
      treatment1 <- pair[1]
      treatment2 <- pair[2]
      
      # Perform t-test for each Target comparing the two acute.treatment levels within the current life.stage
      t_test_results <- delta_Cq_df %>%
        filter(life.stage == stage, acute.treatment %in% c(treatment1, treatment2)) %>%
        group_by(Target) %>%
        summarise(
          t_test_result = list(t.test(delta_Cq ~ acute.treatment))
        ) %>%
        ungroup() %>%
        mutate(
          estimate_diff = sapply(t_test_result, function(x) x$estimate[1] - x$estimate[2]),
          p_value = sapply(t_test_result, function(x) x$p.value),
          asterisk = ifelse(p_value <= 0.05, "*", ""), # Adds asterisk column and asterisk for p-value.
          comparison = paste(stage, treatment1, "vs", treatment2, sep = ".")
        ) %>%
        select(!t_test_result)
      
      acute_treatment_t_test_results_list[[paste(stage, treatment1, treatment2, sep = ".")]] <- t_test_results
    }
  }
}

# Combine results into a single data frame
acute_treatment_t_test_results_df <- bind_rows(acute_treatment_t_test_results_list, .id = "comparison")

# View the results
print(acute_treatment_t_test_results_df)
# A tibble: 14 × 5
   Target           estimate_diff p_value asterisk comparison           
   <chr>                    <dbl>   <dbl> <chr>    <chr>                
 1 ATPsynthase             0.0605   0.687 ""       adult.ambient.high   
 2 DNMT1                   0.314    0.275 ""       adult.ambient.high   
 3 HSP70                   0.276    0.696 ""       adult.ambient.high   
 4 HSP90                   0.499    0.149 ""       adult.ambient.high   
 5 cGAS                    0.329    0.200 ""       adult.ambient.high   
 6 citrate synthase        0.0668   0.622 ""       adult.ambient.high   
 7 viperin                 0.323    0.251 ""       adult.ambient.high   
 8 ATPsynthase            -0.0370   0.738 ""       juvenile.ambient.high
 9 DNMT1                  -0.672    0.121 ""       juvenile.ambient.high
10 HSP70                   0.745    0.319 ""       juvenile.ambient.high
11 HSP90                   0.0450   0.859 ""       juvenile.ambient.high
12 cGAS                   -0.203    0.474 ""       juvenile.ambient.high
13 citrate synthase        0.0399   0.870 ""       juvenile.ambient.high
14 viperin                -0.424    0.304 ""       juvenile.ambient.high

8.1.4 Acute within life stage and conditioning

# Extract unique life.stage levels, excluding 'seed' and 'spat'
unique_life_stages <- unique(delta_Cq_df$life.stage)
#unique_life_stages <- setdiff(unique_life_stages, c("seed", "spat"))

# Extract unique conditioning.treatment levels
unique_conditioning_treatments <- unique(delta_Cq_df$conditioning.treatment)

# Initialize a list to store results
acute_treatment_within_life.stages_conditioning_t_test_results_list <- list()

for (stage in unique_life_stages) {
  for (conditioning in unique_conditioning_treatments) {
    # Extract unique acute.treatment levels within the current life.stage and conditioning.treatment
    unique_treatments <- unique(delta_Cq_df %>% filter(life.stage == stage, conditioning.treatment == conditioning) %>% pull(acute.treatment))
    
    # Check if there are at least 2 unique treatments
    if (length(unique_treatments) >= 2) {
      # Generate all possible pairs of acute.treatment levels
      treatment_pairs <- combn(unique_treatments, 2, simplify = FALSE)
      
      for (pair in treatment_pairs) {
        treatment1 <- pair[1]
        treatment2 <- pair[2]
        
        # Perform t-test for each Target comparing the two acute.treatment levels within the current life.stage and conditioning.treatment
        t_test_results <- delta_Cq_df %>%
          filter(life.stage == stage, conditioning.treatment == conditioning, acute.treatment %in% c(treatment1, treatment2)) %>%
          group_by(Target) %>%
          summarise(
            t_test_result = list(t.test(delta_Cq ~ acute.treatment))
          ) %>%
          ungroup() %>%
          mutate(
            estimate_diff = sapply(t_test_result, function(x) x$estimate[1] - x$estimate[2]),
            p_value = sapply(t_test_result, function(x) x$p.value),
            asterisk = ifelse(p_value <= 0.05, "*", ""), # Adds asterisk column and asterisk for p-value.
            comparison = paste(stage, conditioning, treatment1, "vs", treatment2, sep = ".")
          ) %>%
          select(!t_test_result)
        
        acute_treatment_within_life.stages_conditioning_t_test_results_list[[paste(stage, conditioning, treatment1, treatment2, sep = ".")]] <- t_test_results
      }
    }
  }
}

# Combine results into a single data frame
acute_treatment_within_life.stages_conditioning_t_test_results_df <- bind_rows(acute_treatment_within_life.stages_conditioning_t_test_results_list, .id = "comparison_id")

# View the results
print(acute_treatment_within_life.stages_conditioning_t_test_results_df)
# A tibble: 56 × 6
   comparison_id             Target    estimate_diff p_value asterisk comparison
   <chr>                     <chr>             <dbl>   <dbl> <chr>    <chr>     
 1 seed.treated.high.ambient ATPsynth…         0.658  0.0602 ""       seed.trea…
 2 seed.treated.high.ambient DNMT1            -1.55   0.166  ""       seed.trea…
 3 seed.treated.high.ambient HSP70            -0.133  0.920  ""       seed.trea…
 4 seed.treated.high.ambient HSP90             0.970  0.0699 ""       seed.trea…
 5 seed.treated.high.ambient cGAS             -0.825  0.0627 ""       seed.trea…
 6 seed.treated.high.ambient citrate …        -1.15   0.0114 "*"      seed.trea…
 7 seed.treated.high.ambient viperin          -0.771  0.255  ""       seed.trea…
 8 seed.control.ambient.high ATPsynth…        -0.304  0.125  ""       seed.cont…
 9 seed.control.ambient.high DNMT1            -1.54   0.279  ""       seed.cont…
10 seed.control.ambient.high HSP70            -1.59   0.0190 "*"      seed.cont…
# ℹ 46 more rows

8.2 Plotting

8.2.1 Delta Cq boxplots

8.2.1.1 Lifestage comparisons

# Create box plots for each comparison
unique_comparisons <- unique(life_stage_t_test_results_df$comparison)

for (comparison in unique_comparisons) {
  create_boxplot_delta_Cq(delta_Cq_df, comparison, life_stage_t_test_results_df)
}

8.2.2 Conditioning comparisons

# Create box plots for each comparison
unique_comparisons <- unique(conditioning_treatment_t_test_results_df$comparison)

for (comparison in unique_comparisons) {
  create_boxplot_conditioning(delta_Cq_df, comparison, conditioning_treatment_t_test_results_df)
}

8.2.3 Acute treatment comparisons

# Create box plots for each comparison
unique_comparisons <- unique(acute_treatment_t_test_results_df$comparison)

for (comparison in unique_comparisons) {
  create_boxplot_acute(delta_Cq_df, comparison, acute_treatment_t_test_results_df)
}

8.2.4 Acute within life stage conditioning

# Loop through each comparison in the t-test results and create box plots
for (comparison in unique(acute_treatment_within_life.stages_conditioning_t_test_results_df$comparison)) {
  create_boxplot_acute_conditioning(delta_Cq_df, comparison, acute_treatment_within_life.stages_conditioning_t_test_results_df)
}

9 Delta delta Cq

9.1 Calculations

9.1.1 Conditioning

# Calculate delta_delta_Cq
delta_delta_conditioning_fold_change <- delta_Cq_df %>%
  group_by(life.stage, Target) %>%
  summarize(
    treated_delta_Cq = mean(delta_Cq[conditioning.treatment == "treated"], na.rm = TRUE),
    control_delta_Cq = mean(delta_Cq[conditioning.treatment == "control"], na.rm = TRUE)
  ) %>%
  mutate(delta_delta_Cq = treated_delta_Cq - control_delta_Cq) %>%
  select(life.stage, Target, delta_delta_Cq)

str(delta_delta_conditioning_fold_change)
gropd_df [28 × 3] (S3: grouped_df/tbl_df/tbl/data.frame)
 $ life.stage    : chr [1:28] "adult" "adult" "adult" "adult" ...
 $ Target        : chr [1:28] "ATPsynthase" "DNMT1" "HSP70" "HSP90" ...
 $ delta_delta_Cq: num [1:28] -0.0779 -0.3116 0.941 0.7639 0.1955 ...
 - attr(*, "groups")= tibble [4 × 2] (S3: tbl_df/tbl/data.frame)
  ..$ life.stage: chr [1:4] "adult" "juvenile" "seed" "spat"
  ..$ .rows     : list<int> [1:4] 
  .. ..$ : int [1:7] 1 2 3 4 5 6 7
  .. ..$ : int [1:7] 8 9 10 11 12 13 14
  .. ..$ : int [1:7] 15 16 17 18 19 20 21
  .. ..$ : int [1:7] 22 23 24 25 26 27 28
  .. ..@ ptype: int(0) 
  ..- attr(*, ".drop")= logi TRUE

9.1.2 Acute treatment

# Calculate delta_delta_Cq for acute treatment
delta_delta_Cq_acute_df <- delta_Cq_df %>%
  group_by(life.stage, Target, acute.treatment) %>%
  summarize(
    treated_delta_Cq = mean(delta_Cq[conditioning.treatment == "treated"], na.rm = TRUE),
    control_delta_Cq = mean(delta_Cq[conditioning.treatment == "control"], na.rm = TRUE)
  ) %>%
  mutate(delta_delta_Cq = treated_delta_Cq - control_delta_Cq) %>%
  select(life.stage, Target, acute.treatment, delta_delta_Cq)

str(delta_delta_Cq_acute_df)
gropd_df [56 × 4] (S3: grouped_df/tbl_df/tbl/data.frame)
 $ life.stage     : chr [1:56] "adult" "adult" "adult" "adult" ...
 $ Target         : chr [1:56] "ATPsynthase" "ATPsynthase" "DNMT1" "DNMT1" ...
 $ acute.treatment: chr [1:56] "ambient" "high" "ambient" "high" ...
 $ delta_delta_Cq : num [1:56] -0.112 -0.0438 -0.2467 -0.3765 0.9455 ...
 - attr(*, "groups")= tibble [28 × 3] (S3: tbl_df/tbl/data.frame)
  ..$ life.stage: chr [1:28] "adult" "adult" "adult" "adult" ...
  ..$ Target    : chr [1:28] "ATPsynthase" "DNMT1" "HSP70" "HSP90" ...
  ..$ .rows     : list<int> [1:28] 
  .. ..$ : int [1:2] 1 2
  .. ..$ : int [1:2] 3 4
  .. ..$ : int [1:2] 5 6
  .. ..$ : int [1:2] 7 8
  .. ..$ : int [1:2] 9 10
  .. ..$ : int [1:2] 11 12
  .. ..$ : int [1:2] 13 14
  .. ..$ : int [1:2] 15 16
  .. ..$ : int [1:2] 17 18
  .. ..$ : int [1:2] 19 20
  .. ..$ : int [1:2] 21 22
  .. ..$ : int [1:2] 23 24
  .. ..$ : int [1:2] 25 26
  .. ..$ : int [1:2] 27 28
  .. ..$ : int [1:2] 29 30
  .. ..$ : int [1:2] 31 32
  .. ..$ : int [1:2] 33 34
  .. ..$ : int [1:2] 35 36
  .. ..$ : int [1:2] 37 38
  .. ..$ : int [1:2] 39 40
  .. ..$ : int [1:2] 41 42
  .. ..$ : int [1:2] 43 44
  .. ..$ : int [1:2] 45 46
  .. ..$ : int [1:2] 47 48
  .. ..$ : int [1:2] 49 50
  .. ..$ : int [1:2] 51 52
  .. ..$ : int [1:2] 53 54
  .. ..$ : int [1:2] 55 56
  .. ..@ ptype: int(0) 
  ..- attr(*, ".drop")= logi TRUE

9.1.3 Life stage

# Calculate delta_delta_Cq for life stage comparisons
delta_delta_Cq_life_stage_df <- delta_Cq_df %>%
  group_by(Target, life.stage) %>%
  summarize(mean_delta_Cq = mean(delta_Cq, na.rm = TRUE)) %>%
  ungroup() %>%
  pivot_wider(names_from = life.stage, values_from = mean_delta_Cq) %>%
  mutate(
    delta_delta_Cq_adult_vs_seed = adult - seed,
    delta_delta_Cq_spat_vs_seed = spat - seed,
    delta_delta_Cq_adult_vs_spat = adult - spat
  ) %>%
  pivot_longer(cols = starts_with("delta_delta_Cq_"), names_to = "comparison", values_to = "delta_delta_Cq") %>%
  filter(!is.na(delta_delta_Cq))

# Display the structure of the resulting data frame
str(delta_delta_Cq_life_stage_df)
tibble [21 × 7] (S3: tbl_df/tbl/data.frame)
 $ Target        : chr [1:21] "ATPsynthase" "ATPsynthase" "ATPsynthase" "DNMT1" ...
 $ adult         : num [1:21] 0.48 0.48 0.48 6.17 6.17 ...
 $ juvenile      : num [1:21] 0.378 0.378 0.378 5.808 5.808 ...
 $ seed          : num [1:21] 0.17 0.17 0.17 6.24 6.24 ...
 $ spat          : num [1:21] 0.337 0.337 0.337 6.443 6.443 ...
 $ comparison    : chr [1:21] "delta_delta_Cq_adult_vs_seed" "delta_delta_Cq_spat_vs_seed" "delta_delta_Cq_adult_vs_spat" "delta_delta_Cq_adult_vs_seed" ...
 $ delta_delta_Cq: num [1:21] 0.3098 0.1664 0.1433 -0.0736 0.2019 ...

9.1.4 Calculate delta delta acute treatments within lifestage and conditioning

# Calculate delta_delta_Cq for acute treatment comparisons within each life stage and conditioning treatment
delta_delta_Cq_acute_within_life_stage_conditioning_df <- delta_Cq_df %>%
  group_by(life.stage, conditioning.treatment, Target, acute.treatment) %>%
  summarize(mean_delta_Cq = mean(delta_Cq, na.rm = TRUE)) %>%
  ungroup() %>%
  pivot_wider(names_from = acute.treatment, values_from = mean_delta_Cq) %>%
  mutate(delta_delta_Cq_high_vs_ambient = high - ambient) %>%
  pivot_longer(cols = starts_with("delta_delta_Cq_"), names_to = "comparison", values_to = "delta_delta_Cq") %>%
  filter(!is.na(delta_delta_Cq))

# Display the structure of the resulting data frame
str(delta_delta_Cq_acute_within_life_stage_conditioning_df)
tibble [56 × 7] (S3: tbl_df/tbl/data.frame)
 $ life.stage            : chr [1:56] "adult" "adult" "adult" "adult" ...
 $ conditioning.treatment: chr [1:56] "control" "control" "control" "control" ...
 $ Target                : chr [1:56] "ATPsynthase" "DNMT1" "HSP70" "HSP90" ...
 $ ambient               : num [1:56] 0.566 6.448 3.944 1.259 5.207 ...
 $ high                  : num [1:56] 0.472 6.199 3.673 0.29 4.609 ...
 $ comparison            : chr [1:56] "delta_delta_Cq_high_vs_ambient" "delta_delta_Cq_high_vs_ambient" "delta_delta_Cq_high_vs_ambient" "delta_delta_Cq_high_vs_ambient" ...
 $ delta_delta_Cq        : num [1:56] -0.0946 -0.2492 -0.2715 -0.969 -0.5983 ...

9.1.5 Calculate the fold change life stage comparison

# Calculate fold change and output to a new data frame
fold_change_life_stage_df <- delta_delta_Cq_life_stage_df %>%
  mutate(fold_change = 2^(-delta_delta_Cq))

# Display the structure of the resulting data frame
str(fold_change_life_stage_df)
tibble [21 × 8] (S3: tbl_df/tbl/data.frame)
 $ Target        : chr [1:21] "ATPsynthase" "ATPsynthase" "ATPsynthase" "DNMT1" ...
 $ adult         : num [1:21] 0.48 0.48 0.48 6.17 6.17 ...
 $ juvenile      : num [1:21] 0.378 0.378 0.378 5.808 5.808 ...
 $ seed          : num [1:21] 0.17 0.17 0.17 6.24 6.24 ...
 $ spat          : num [1:21] 0.337 0.337 0.337 6.443 6.443 ...
 $ comparison    : chr [1:21] "delta_delta_Cq_adult_vs_seed" "delta_delta_Cq_spat_vs_seed" "delta_delta_Cq_adult_vs_spat" "delta_delta_Cq_adult_vs_seed" ...
 $ delta_delta_Cq: num [1:21] 0.3098 0.1664 0.1433 -0.0736 0.2019 ...
 $ fold_change   : num [1:21] 0.807 0.891 0.905 1.052 0.869 ...

9.1.6 Calculate the fold change conditioning comparison

delta_delta_conditioning_fold_change <- delta_delta_conditioning_fold_change %>%
  mutate(fold_change = 2^(-delta_delta_Cq)) %>% 
  distinct(Target, fold_change)

str(delta_delta_conditioning_fold_change)
gropd_df [28 × 3] (S3: grouped_df/tbl_df/tbl/data.frame)
 $ life.stage : chr [1:28] "adult" "adult" "adult" "adult" ...
 $ Target     : chr [1:28] "ATPsynthase" "DNMT1" "HSP70" "HSP90" ...
 $ fold_change: num [1:28] 1.055 1.241 0.521 0.589 0.873 ...
 - attr(*, "groups")= tibble [4 × 2] (S3: tbl_df/tbl/data.frame)
  ..$ life.stage: chr [1:4] "adult" "juvenile" "seed" "spat"
  ..$ .rows     : list<int> [1:4] 
  .. ..$ : int [1:7] 1 2 3 4 5 6 7
  .. ..$ : int [1:7] 8 9 10 11 12 13 14
  .. ..$ : int [1:7] 15 16 17 18 19 20 21
  .. ..$ : int [1:7] 22 23 24 25 26 27 28
  .. ..@ ptype: int(0) 
  ..- attr(*, ".drop")= logi TRUE

9.1.7 Calculate the fold change acute comparison

# Calculate fold change for acute treatment
delta_delta_acute_fold_change <- delta_delta_Cq_acute_df %>%
  mutate(fold_change = 2^(-delta_delta_Cq)) %>%
  distinct(life.stage, Target, acute.treatment, fold_change)

# Display the structure of the resulting data frame
str(delta_delta_acute_fold_change)
gropd_df [56 × 4] (S3: grouped_df/tbl_df/tbl/data.frame)
 $ life.stage     : chr [1:56] "adult" "adult" "adult" "adult" ...
 $ Target         : chr [1:56] "ATPsynthase" "ATPsynthase" "DNMT1" "DNMT1" ...
 $ acute.treatment: chr [1:56] "ambient" "high" "ambient" "high" ...
 $ fold_change    : num [1:56] 1.081 1.031 1.186 1.298 0.519 ...
 - attr(*, "groups")= tibble [28 × 3] (S3: tbl_df/tbl/data.frame)
  ..$ life.stage: chr [1:28] "adult" "adult" "adult" "adult" ...
  ..$ Target    : chr [1:28] "ATPsynthase" "DNMT1" "HSP70" "HSP90" ...
  ..$ .rows     : list<int> [1:28] 
  .. ..$ : int [1:2] 1 2
  .. ..$ : int [1:2] 3 4
  .. ..$ : int [1:2] 5 6
  .. ..$ : int [1:2] 7 8
  .. ..$ : int [1:2] 9 10
  .. ..$ : int [1:2] 11 12
  .. ..$ : int [1:2] 13 14
  .. ..$ : int [1:2] 15 16
  .. ..$ : int [1:2] 17 18
  .. ..$ : int [1:2] 19 20
  .. ..$ : int [1:2] 21 22
  .. ..$ : int [1:2] 23 24
  .. ..$ : int [1:2] 25 26
  .. ..$ : int [1:2] 27 28
  .. ..$ : int [1:2] 29 30
  .. ..$ : int [1:2] 31 32
  .. ..$ : int [1:2] 33 34
  .. ..$ : int [1:2] 35 36
  .. ..$ : int [1:2] 37 38
  .. ..$ : int [1:2] 39 40
  .. ..$ : int [1:2] 41 42
  .. ..$ : int [1:2] 43 44
  .. ..$ : int [1:2] 45 46
  .. ..$ : int [1:2] 47 48
  .. ..$ : int [1:2] 49 50
  .. ..$ : int [1:2] 51 52
  .. ..$ : int [1:2] 53 54
  .. ..$ : int [1:2] 55 56
  .. ..@ ptype: int(0) 
  ..- attr(*, ".drop")= logi TRUE

9.1.8 Calculate fold change acute treatments within lifestage and conditioning

# Calculate fold change for acute treatment comparisons within each life stage and conditioning treatment
fold_change_acute_within_life_stage_conditioning_df <- delta_delta_Cq_acute_within_life_stage_conditioning_df %>%
  mutate(fold_change = 2^(-delta_delta_Cq))

# Display the structure of the resulting data frame
str(fold_change_acute_within_life_stage_conditioning_df)
tibble [56 × 8] (S3: tbl_df/tbl/data.frame)
 $ life.stage            : chr [1:56] "adult" "adult" "adult" "adult" ...
 $ conditioning.treatment: chr [1:56] "control" "control" "control" "control" ...
 $ Target                : chr [1:56] "ATPsynthase" "DNMT1" "HSP70" "HSP90" ...
 $ ambient               : num [1:56] 0.566 6.448 3.944 1.259 5.207 ...
 $ high                  : num [1:56] 0.472 6.199 3.673 0.29 4.609 ...
 $ comparison            : chr [1:56] "delta_delta_Cq_high_vs_ambient" "delta_delta_Cq_high_vs_ambient" "delta_delta_Cq_high_vs_ambient" "delta_delta_Cq_high_vs_ambient" ...
 $ delta_delta_Cq        : num [1:56] -0.0946 -0.2492 -0.2715 -0.969 -0.5983 ...
 $ fold_change           : num [1:56] 1.07 1.19 1.21 1.96 1.51 ...

9.2 Plotting fold changes

9.2.1 Acute comparisons within lifestage and conditioning

library(ggplot2)

# Generate bar plots for each group of comparison within each life stage and conditioning treatment
plot_list <- fold_change_acute_within_life_stage_conditioning_df %>%
  split(list(.$life.stage, .$conditioning.treatment, .$comparison)) %>%
  lapply(function(df) {
    life_stage <- unique(df$life.stage)
    conditioning_treatment <- unique(df$conditioning.treatment)
    comparison_title <- gsub("delta_delta_Cq_", "", unique(df$comparison))
    comparison_title <- gsub("_vs_", " vs. ", comparison_title)
    ggplot(df, aes(x = Target, y = fold_change)) +
      geom_bar(stat = "identity") +
      labs(title = paste("Gene Expression -", life_stage, "-", conditioning_treatment, "-", comparison_title), 
           x = "Target", y = "Fold Change") +
      theme_minimal() +
      theme(axis.text.x = element_text(angle = 45, hjust = 1))
  })

# Display the plots
for (plot in plot_list) {
  print(plot)
}

9.2.2 Life stage comparisons

# Generate bar plots for each group of comparison
plot_list <- fold_change_life_stage_df %>%
  split(.$comparison) %>%
  lapply(function(df) {
    comparison_title <- gsub("delta_delta_Cq_", "", unique(df$comparison))
    comparison_title <- gsub("_vs_", " vs. ", comparison_title)
    ggplot(df, aes(x = Target, y = fold_change)) +
      geom_bar(stat = "identity") +
      labs(title = paste("Gene Expression -", comparison_title), x = "Target", y = "Fold Change") +
      theme_minimal() +
      theme(axis.text.x = element_text(angle = 45, hjust = 1))
  })

# Display the plots
for (plot in plot_list) {
  print(plot)
}

9.2.3 Conditioning comparisons

9.2.4 Line plot conditioning comparisons across lifestages

9.2.5 Acute treatment comparison

10 Running linear models

10.1 ANOVA models

hist(delta_Cq_df$delta_Cq)

Run an anova model to test for effects of lifestage, conditioning, and acute treatment on delta Cq values for each target.

10.1.1 ATP synthase

ATP synthase is an enzyme complex that functions to synthesize adenosine triphosphate (ATP) from adenosine diphosphate (ADP) and inorganic phosphate (Pi), essentially generating the cell’s primary energy currency by harnessing the energy from a proton gradient across a membrane.

library(car)
library(emmeans)

model<-delta_Cq_df%>%
  filter(Target=="ATPsynthase")%>%
  
  aov(delta_Cq ~ life.stage * conditioning.treatment * acute.treatment, data=.)

summary(model)
                                                  Df Sum Sq Mean Sq F value
life.stage                                         3  1.127  0.3755   2.589
conditioning.treatment                             1  0.118  0.1180   0.814
acute.treatment                                    1  0.367  0.3665   2.527
life.stage:conditioning.treatment                  3  0.116  0.0387   0.267
life.stage:acute.treatment                         3  0.487  0.1624   1.119
conditioning.treatment:acute.treatment             1  0.264  0.2640   1.820
life.stage:conditioning.treatment:acute.treatment  3  0.745  0.2482   1.711
Residuals                                         79 11.460  0.1451        
                                                  Pr(>F)  
life.stage                                        0.0588 .
conditioning.treatment                            0.3698  
acute.treatment                                   0.1159  
life.stage:conditioning.treatment                 0.8492  
life.stage:acute.treatment                        0.3464  
conditioning.treatment:acute.treatment            0.1812  
life.stage:conditioning.treatment:acute.treatment 0.1715  
Residuals                                                 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
qqPlot(model$residuals)

[1] 31 77
leveneTest(model$residuals ~ life.stage*conditioning.treatment*acute.treatment, data=delta_Cq_df%>%filter(Target=="ATPsynthase"))
Levene's Test for Homogeneity of Variance (center = median)
      Df F value Pr(>F)
group 15  0.7829 0.6923
      79               

No significant effects.

10.1.2 DNMT1

The DNMT1 gene provides instructions for making an enzyme called DNA methyltransferase 1. This enzyme is involved in DNA methylation, which is the addition of methyl groups, consisting of one carbon atom and three hydrogen atoms, to DNA molecules.

model<-delta_Cq_df%>%
  filter(Target=="DNMT1")%>%
  
  aov(delta_Cq ~ life.stage * conditioning.treatment * acute.treatment, data=.)

summary(model)
                                                  Df Sum Sq Mean Sq F value
life.stage                                         3   4.78   1.592   1.296
conditioning.treatment                             1   0.20   0.201   0.164
acute.treatment                                    1   3.87   3.869   3.149
life.stage:conditioning.treatment                  3   6.67   2.222   1.809
life.stage:acute.treatment                         3  10.00   3.334   2.714
conditioning.treatment:acute.treatment             1   0.96   0.959   0.781
life.stage:conditioning.treatment:acute.treatment  3   6.80   2.266   1.845
Residuals                                         79  97.06   1.229        
                                                  Pr(>F)  
life.stage                                        0.2817  
conditioning.treatment                            0.6868  
acute.treatment                                   0.0798 .
life.stage:conditioning.treatment                 0.1524  
life.stage:acute.treatment                        0.0504 .
conditioning.treatment:acute.treatment            0.3796  
life.stage:conditioning.treatment:acute.treatment 0.1459  
Residuals                                                 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
qqPlot(model$residuals)

[1]  7 21
leveneTest(model$residuals ~ life.stage*conditioning.treatment*acute.treatment, data=delta_Cq_df%>%filter(Target=="DNMT1"))
Levene's Test for Homogeneity of Variance (center = median)
      Df F value Pr(>F)
group 15  0.8095  0.664
      79               

No significant effects.

10.1.3 HSP70

Heat Shock Protein 70 (Hsp70) is a molecular chaperone that plays crucial roles in maintaining cellular protein homeostasis and protecting cells from stress.

model<-delta_Cq_df%>%
  filter(Target=="HSP70")%>%
  
  aov(delta_Cq ~ life.stage * conditioning.treatment * acute.treatment, data=.)

summary(model)
                                                  Df Sum Sq Mean Sq F value
life.stage                                         3  13.48   4.494   1.554
conditioning.treatment                             1   0.45   0.445   0.154
acute.treatment                                    1   1.71   1.710   0.591
life.stage:conditioning.treatment                  3  10.31   3.438   1.189
life.stage:acute.treatment                         3   6.61   2.203   0.762
conditioning.treatment:acute.treatment             1  21.29  21.286   7.361
life.stage:conditioning.treatment:acute.treatment  3  16.05   5.349   1.850
Residuals                                         79 228.45   2.892        
                                                   Pr(>F)   
life.stage                                        0.20717   
conditioning.treatment                            0.69582   
acute.treatment                                   0.44418   
life.stage:conditioning.treatment                 0.31938   
life.stage:acute.treatment                        0.51889   
conditioning.treatment:acute.treatment            0.00818 **
life.stage:conditioning.treatment:acute.treatment 0.14496   
Residuals                                                   
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
qqPlot(model$residuals)

[1] 94  9
leveneTest(model$residuals ~ life.stage*conditioning.treatment*acute.treatment, data=delta_Cq_df%>%filter(Target=="HSP70"))
Levene's Test for Homogeneity of Variance (center = median)
      Df F value Pr(>F)
group 15    0.61 0.8584
      79               
emm<-emmeans(model, ~ conditioning.treatment:acute.treatment | life.stage)
pairs(emm)
life.stage = adult:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient   -0.946 0.850 79  -1.112  0.6832
 control ambient - control high       0.271 0.850 79   0.319  0.9887
 control ambient - treated high      -0.665 0.850 79  -0.782  0.8624
 treated ambient - control high       1.217 0.850 79   1.431  0.4838
 treated ambient - treated high       0.281 0.850 79   0.330  0.9875
 control high - treated high         -0.936 0.850 79  -1.101  0.6898

life.stage = juvenile:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient   -1.304 0.982 79  -1.329  0.5477
 control ambient - control high      -0.603 0.982 79  -0.614  0.9274
 control ambient - treated high       0.788 0.982 79   0.803  0.8529
 treated ambient - control high       0.702 0.982 79   0.715  0.8910
 treated ambient - treated high       2.093 0.982 79   2.131  0.1522
 control high - treated high          1.391 0.982 79   1.417  0.4928

life.stage = seed:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient   -0.608 0.982 79  -0.619  0.9257
 control ambient - control high      -1.589 1.202 79  -1.321  0.5523
 control ambient - treated high      -0.741 1.202 79  -0.616  0.9267
 treated ambient - control high      -0.981 1.202 79  -0.816  0.8469
 treated ambient - treated high      -0.133 1.202 79  -0.110  0.9995
 control high - treated high          0.848 1.388 79   0.611  0.9284

life.stage = spat:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient   -1.236 1.030 79  -1.200  0.6286
 control ambient - control high      -1.873 1.098 79  -1.707  0.3271
 control ambient - treated high       1.255 0.982 79   1.278  0.5794
 treated ambient - control high      -0.638 1.141 79  -0.559  0.9438
 treated ambient - treated high       2.491 1.030 79   2.419  0.0817
 control high - treated high          3.128 1.098 79   2.850  0.0280

P value adjustment: tukey method for comparing a family of 4 estimates 

Significant effect of conditioning x acute treatment.

10.1.4 HSP90

Heat shock protein 90 (Hsp90) is a molecular chaperone that helps proteins fold, mature, and remain active. Hsp90 also helps regulate signaling networks and is involved in many cellular processes.

model<-delta_Cq_df%>%
  filter(Target=="HSP90")%>%
  
  aov(delta_Cq ~ life.stage * conditioning.treatment * acute.treatment, data=.)

summary(model)
                                                  Df Sum Sq Mean Sq F value
life.stage                                         3  22.10   7.368  14.629
conditioning.treatment                             1   0.98   0.983   1.952
acute.treatment                                    1  12.31  12.308  24.438
life.stage:conditioning.treatment                  3   4.77   1.591   3.159
life.stage:acute.treatment                         3   6.58   2.192   4.353
conditioning.treatment:acute.treatment             1   0.10   0.103   0.204
life.stage:conditioning.treatment:acute.treatment  3   3.20   1.067   2.118
Residuals                                         79  39.79   0.504        
                                                    Pr(>F)    
life.stage                                        1.15e-07 ***
conditioning.treatment                             0.16627    
acute.treatment                                   4.22e-06 ***
life.stage:conditioning.treatment                  0.02921 *  
life.stage:acute.treatment                         0.00686 ** 
conditioning.treatment:acute.treatment             0.65283    
life.stage:conditioning.treatment:acute.treatment  0.10451    
Residuals                                                     
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
qqPlot(model$residuals)

[1] 94 80
leveneTest(model$residuals ~ life.stage*conditioning.treatment*acute.treatment, data=delta_Cq_df%>%filter(Target=="HSP90"))
Levene's Test for Homogeneity of Variance (center = median)
      Df F value Pr(>F)
group 15  1.5079 0.1226
      79               
emm<-emmeans(model, ~ conditioning.treatment:acute.treatment | life.stage)
pairs(emm)
life.stage = adult:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient  -0.2939 0.355 79  -0.828  0.8409
 control ambient - control high      0.9690 0.355 79   2.731  0.0382
 control ambient - treated high     -0.2648 0.355 79  -0.746  0.8780
 treated ambient - control high      1.2630 0.355 79   3.559  0.0035
 treated ambient - treated high      0.0292 0.355 79   0.082  0.9998
 control high - treated high        -1.2338 0.355 79  -3.477  0.0045

life.stage = juvenile:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient  -0.1098 0.410 79  -0.268  0.9932
 control ambient - control high     -0.0451 0.410 79  -0.110  0.9995
 control ambient - treated high      0.0254 0.410 79   0.062  0.9999
 treated ambient - control high      0.0647 0.410 79   0.158  0.9986
 treated ambient - treated high      0.1352 0.410 79   0.330  0.9875
 control high - treated high         0.0704 0.410 79   0.172  0.9982

life.stage = seed:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient  -0.1505 0.410 79  -0.367  0.9829
 control ambient - control high      1.4140 0.502 79   2.818  0.0305
 control ambient - treated high      0.8191 0.502 79   1.632  0.3666
 treated ambient - control high      1.5645 0.502 79   3.118  0.0133
 treated ambient - treated high      0.9696 0.502 79   1.932  0.2231
 control high - treated high        -0.5948 0.579 79  -1.027  0.7344

life.stage = spat:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient  -0.1549 0.430 79  -0.360  0.9839
 control ambient - control high      0.8926 0.458 79   1.949  0.2165
 control ambient - treated high      1.7432 0.410 79   4.255  0.0003
 treated ambient - control high      1.0475 0.476 79   2.200  0.1321
 treated ambient - treated high      1.8981 0.430 79   4.417  0.0002
 control high - treated high         0.8506 0.458 79   1.857  0.2551

P value adjustment: tukey method for comparing a family of 4 estimates 

Significant effect of lifestage x acute treatment, lifestage x conditioning treatment, acute treatment, and lifestage.

10.1.5 cGAS

The cGAS gene is involved in several processes, including cellular response to exogenous dsRNA, positive regulation of intracellular signal transduction, and regulation of defense response.

model<-delta_Cq_df%>%
  filter(Target=="cGAS")%>%
  
  aov(delta_Cq ~ life.stage * conditioning.treatment * acute.treatment, data=.)

summary(model)
                                                  Df Sum Sq Mean Sq F value
life.stage                                         3   5.18  1.7253   2.721
conditioning.treatment                             1   0.01  0.0147   0.023
acute.treatment                                    1   0.37  0.3707   0.585
life.stage:conditioning.treatment                  3   0.57  0.1901   0.300
life.stage:acute.treatment                         3   6.68  2.2251   3.510
conditioning.treatment:acute.treatment             1   0.84  0.8435   1.330
life.stage:conditioning.treatment:acute.treatment  3   4.27  1.4238   2.246
Residuals                                         79  50.09  0.6340        
                                                  Pr(>F)  
life.stage                                        0.0499 *
conditioning.treatment                            0.8794  
acute.treatment                                   0.4468  
life.stage:conditioning.treatment                 0.8254  
life.stage:acute.treatment                        0.0190 *
conditioning.treatment:acute.treatment            0.2522  
life.stage:conditioning.treatment:acute.treatment 0.0894 .
Residuals                                                 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
qqPlot(model$residuals)

[1] 70 10
leveneTest(model$residuals ~ life.stage*conditioning.treatment*acute.treatment, data=delta_Cq_df%>%filter(Target=="cGAS"))
Levene's Test for Homogeneity of Variance (center = median)
      Df F value Pr(>F)
group 15   0.817  0.656
      79               
emm<-emmeans(model, ~ conditioning.treatment:acute.treatment | life.stage)
pairs(emm)
life.stage = adult:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient   0.0739 0.398 79   0.186  0.9977
 control ambient - control high      0.5983 0.398 79   1.503  0.4407
 control ambient - treated high      0.1334 0.398 79   0.335  0.9869
 treated ambient - control high      0.5244 0.398 79   1.317  0.5549
 treated ambient - treated high      0.0595 0.398 79   0.150  0.9988
 control high - treated high        -0.4649 0.398 79  -1.168  0.6489

life.stage = juvenile:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient  -0.0378 0.460 79  -0.082  0.9998
 control ambient - control high     -0.2947 0.460 79  -0.641  0.9183
 control ambient - treated high     -0.1488 0.460 79  -0.324  0.9882
 treated ambient - control high     -0.2569 0.460 79  -0.559  0.9439
 treated ambient - treated high     -0.1110 0.460 79  -0.241  0.9950
 control high - treated high         0.1459 0.460 79   0.317  0.9888

life.stage = seed:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient  -0.3407 0.460 79  -0.741  0.8802
 control ambient - control high     -1.6144 0.563 79  -2.867  0.0267
 control ambient - treated high     -1.1659 0.563 79  -2.071  0.1717
 treated ambient - control high     -1.2737 0.563 79  -2.262  0.1158
 treated ambient - treated high     -0.8252 0.563 79  -1.466  0.4629
 control high - treated high         0.4485 0.650 79   0.690  0.9007

life.stage = spat:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient  -0.6338 0.482 79  -1.315  0.5565
 control ambient - control high     -0.8533 0.514 79  -1.660  0.3515
 control ambient - treated high      0.2519 0.460 79   0.548  0.9468
 treated ambient - control high     -0.2195 0.534 79  -0.411  0.9764
 treated ambient - treated high      0.8857 0.482 79   1.837  0.2639
 control high - treated high         1.1053 0.514 79   2.150  0.1464

P value adjustment: tukey method for comparing a family of 4 estimates 

Significant effect of lifestage x acute treatment and lifestage.

10.1.6 Citrate synthase

Citrate synthase is important for energy production in the TCA cycle and is linked to the electron transport chain. It is also used as an enzyme marker for intact mitochondria.

model<-delta_Cq_df%>%
  filter(Target=="citrate synthase")%>%
  
  aov(delta_Cq ~ life.stage * conditioning.treatment * acute.treatment, data=.)

summary(model)
                                                  Df Sum Sq Mean Sq F value
life.stage                                         3  1.383   0.461   1.985
conditioning.treatment                             1  0.210   0.210   0.904
acute.treatment                                    1  5.025   5.025  21.641
life.stage:conditioning.treatment                  3  0.146   0.049   0.210
life.stage:acute.treatment                         3 10.632   3.544  15.262
conditioning.treatment:acute.treatment             1  0.012   0.012   0.052
life.stage:conditioning.treatment:acute.treatment  3  1.430   0.477   2.053
Residuals                                         79 18.345   0.232        
                                                    Pr(>F)    
life.stage                                           0.123    
conditioning.treatment                               0.345    
acute.treatment                                   1.30e-05 ***
life.stage:conditioning.treatment                    0.889    
life.stage:acute.treatment                        6.36e-08 ***
conditioning.treatment:acute.treatment               0.820    
life.stage:conditioning.treatment:acute.treatment    0.113    
Residuals                                                     
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
qqPlot(model$residuals)

[1] 10 93
leveneTest(model$residuals ~ life.stage*conditioning.treatment*acute.treatment, data=delta_Cq_df%>%filter(Target=="citrate synthase"))
Levene's Test for Homogeneity of Variance (center = median)
      Df F value Pr(>F)
group 15  0.7099 0.7674
      79               
emm<-emmeans(model, ~ conditioning.treatment:acute.treatment | life.stage)
pairs(emm)
life.stage = adult:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient  0.31754 0.241 79   1.318  0.5544
 control ambient - control high     0.30936 0.241 79   1.284  0.5758
 control ambient - treated high     0.14178 0.241 79   0.588  0.9353
 treated ambient - control high    -0.00818 0.241 79  -0.034  1.0000
 treated ambient - treated high    -0.17576 0.241 79  -0.729  0.8850
 control high - treated high       -0.16758 0.241 79  -0.696  0.8985

life.stage = juvenile:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient  0.16164 0.278 79   0.581  0.9375
 control ambient - control high     0.04161 0.278 79   0.150  0.9988
 control ambient - treated high     0.19990 0.278 79   0.719  0.8894
 treated ambient - control high    -0.12003 0.278 79  -0.431  0.9729
 treated ambient - treated high     0.03826 0.278 79   0.138  0.9991
 control high - treated high        0.15830 0.278 79   0.569  0.9410

life.stage = seed:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient -0.33494 0.278 79  -1.204  0.6262
 control ambient - control high    -2.10686 0.341 79  -6.183  <.0001
 control ambient - treated high    -1.48124 0.341 79  -4.347  0.0002
 treated ambient - control high    -1.77193 0.341 79  -5.200  <.0001
 treated ambient - treated high    -1.14630 0.341 79  -3.364  0.0064
 control high - treated high        0.62562 0.393 79   1.590  0.3901

life.stage = spat:
 contrast                          estimate    SE df t.ratio p.value
 control ambient - treated ambient  0.37761 0.292 79   1.294  0.5694
 control ambient - control high    -0.89118 0.311 79  -2.865  0.0269
 control ambient - treated high    -0.70973 0.278 79  -2.551  0.0599
 treated ambient - control high    -1.26879 0.323 79  -3.925  0.0010
 treated ambient - treated high    -1.08734 0.292 79  -3.726  0.0020
 control high - treated high        0.18145 0.311 79   0.583  0.9368

P value adjustment: tukey method for comparing a family of 4 estimates 

Significant effect of acute treatment and lifestage x acute treatment.

All tests pass normality and homogeneity of variance. ANOVA tests are appropriate.

10.2 Plotting

Display plot of acute x conditioning treatment faceted for each lifestage for each target.

Show sample size for each group.

delta_Cq_df%>%
  group_by(life.stage, acute.treatment, conditioning.treatment)%>%
  summarise(n=length(unique(Sample)))
# A tibble: 16 × 4
# Groups:   life.stage, acute.treatment [8]
   life.stage acute.treatment conditioning.treatment     n
   <chr>      <chr>           <chr>                  <int>
 1 adult      ambient         control                    8
 2 adult      ambient         treated                    8
 3 adult      high            control                    8
 4 adult      high            treated                    8
 5 juvenile   ambient         control                    6
 6 juvenile   ambient         treated                    6
 7 juvenile   high            control                    6
 8 juvenile   high            treated                    6
 9 seed       ambient         control                    6
10 seed       ambient         treated                    6
11 seed       high            control                    3
12 seed       high            treated                    3
13 spat       ambient         control                    6
14 spat       ambient         treated                    5
15 spat       high            control                    4
16 spat       high            treated                    6

Note that sample sizes for spat, seed, or juveniles that are <6 are due to lack of RNA isolated from the samples.

Adults were all sampled from one family (Pink). Previous flow cytometry was unclear as to diploid or triploid classification. We have extracted DNA that we can use to verify ploidy.

10.2.1 ATP synthase: No effects

plot1<-delta_Cq_df%>%
  filter(Target=="ATPsynthase")%>%
  
  group_by(Target, life.stage, acute.treatment, conditioning.treatment)%>%
  summarise(mean=mean(delta_Cq, na.rm=TRUE), se=sd(delta_Cq, na.rm=TRUE)/sqrt(length(delta_Cq)))%>%
  
  ggplot(aes(x=acute.treatment, y=mean, colour=conditioning.treatment))+
  facet_grid(~life.stage)+
  scale_colour_manual(values=c("darkgray", "orange"))+
  geom_point()+
  geom_line(aes(group=conditioning.treatment))+
  geom_errorbar(aes(ymin=mean-se, ymax=mean+se), width=0.1)+
  ggtitle("ATP synthase (no sign. effects)")+
  ylab("Delta Cq")+
  ylim(-0.5,1.5)+
  geom_hline(yintercept=0, linetype="dashed")+
  theme_classic();plot1

10.2.2 DNMT1: No effects

plot2<-delta_Cq_df%>%
  filter(Target=="DNMT1")%>%
  
  group_by(Target, life.stage, acute.treatment, conditioning.treatment)%>%
  summarise(mean=mean(delta_Cq, na.rm=TRUE), se=sd(delta_Cq, na.rm=TRUE)/sqrt(length(delta_Cq)))%>%
  
  ggplot(aes(x=acute.treatment, y=mean, colour=conditioning.treatment))+
  facet_grid(~life.stage)+
  geom_point()+
  scale_colour_manual(values=c("darkgray", "orange"))+
  geom_line(aes(group=conditioning.treatment))+
  geom_errorbar(aes(ymin=mean-se, ymax=mean+se), width=0.1)+
  ggtitle("DMNT1 (no sign. effects)")+
  ylab("Delta Cq")+
  geom_hline(yintercept=0, linetype="dashed")+
  ylim(0,9)+
  theme_classic();plot2

10.2.3 HSP70: Significant effect of conditioning x acute treatment.

plot3<-delta_Cq_df%>%
  filter(Target=="HSP70")%>%
  
  group_by(Target, life.stage, acute.treatment, conditioning.treatment)%>%
  summarise(mean=mean(delta_Cq, na.rm=TRUE), se=sd(delta_Cq, na.rm=TRUE)/sqrt(length(delta_Cq)))%>%
  
  ggplot(aes(x=acute.treatment, y=mean, colour=conditioning.treatment))+
  facet_grid(~life.stage)+
  scale_colour_manual(values=c("darkgray", "orange"))+
  geom_point()+
  geom_line(aes(group=conditioning.treatment))+
  geom_errorbar(aes(ymin=mean-se, ymax=mean+se), width=0.1)+
  ggtitle("HSP70  (sign. conditioning x acute treatment)")+
  ylab("Delta Cq")+
  ylim(0,8)+
  geom_hline(yintercept=0, linetype="dashed")+
  theme_classic();plot3

plot3a<-delta_Cq_df%>%
  filter(Target=="HSP70")%>%
  
  group_by(Target, acute.treatment, conditioning.treatment)%>%
  summarise(mean=mean(delta_Cq, na.rm=TRUE), se=sd(delta_Cq, na.rm=TRUE)/sqrt(length(delta_Cq)))%>%
  
  ggplot(aes(x=acute.treatment, y=mean, colour=conditioning.treatment))+
  geom_point()+
  scale_colour_manual(values=c("darkgray", "orange"))+
  geom_line(aes(group=conditioning.treatment))+
  geom_errorbar(aes(ymin=mean-se, ymax=mean+se), width=0.1)+
  ggtitle("HSP70  (sign. conditioning x acute treatment)")+
  ylab("Delta Cq")+
  geom_hline(yintercept=0, linetype="dashed")+
  ylim(0,8)+
  theme_classic();plot3a

10.2.4 HSP90: Significant effect of lifestage x acute treatment, lifestage x conditioning treatment, acute treatment, and lifestage.

plot4<-delta_Cq_df%>%
  filter(Target=="HSP90")%>%
  
  group_by(Target, life.stage, acute.treatment, conditioning.treatment)%>%
  summarise(mean=mean(delta_Cq, na.rm=TRUE), se=sd(delta_Cq, na.rm=TRUE)/sqrt(length(delta_Cq)))%>%
  
  ggplot(aes(x=acute.treatment, y=mean, colour=conditioning.treatment))+
  facet_grid(~life.stage)+
  scale_colour_manual(values=c("darkgray", "orange"))+
  geom_point()+
  geom_line(aes(group=conditioning.treatment))+
  geom_errorbar(aes(ymin=mean-se, ymax=mean+se), width=0.1)+
  ggtitle("HSP90  (sign. lifestage x acute & lifestage x conditioning treatment)")+
  ylab("Delta Cq")+
  ylim(-2,2.5)+
  geom_hline(yintercept=0, linetype="dashed")+
  theme_classic();plot4

10.2.5 cGAS: Significant effect of lifestage x acute treatment and lifestage.

plot5<-delta_Cq_df%>%
  filter(Target=="cGAS")%>%
  
  group_by(Target, life.stage, acute.treatment, conditioning.treatment)%>%
  summarise(mean=mean(delta_Cq, na.rm=TRUE), se=sd(delta_Cq, na.rm=TRUE)/sqrt(length(delta_Cq)))%>%
  
  ggplot(aes(x=acute.treatment, y=mean, colour=conditioning.treatment))+
  facet_grid(~life.stage)+
  scale_colour_manual(values=c("darkgray", "orange"))+
  geom_point()+
  geom_line(aes(group=conditioning.treatment))+
  geom_errorbar(aes(ymin=mean-se, ymax=mean+se), width=0.1)+
  ggtitle("cGAS  (sign. lifestage x acute treatment)")+
  ylab("Delta Cq")+
  ylim(2,8)+
  geom_hline(yintercept=0, linetype="dashed")+
  theme_classic();plot5

10.2.6 Citrate synthase: Significant effect of acute treatment and lifestage x acute treatment.

plot6<-delta_Cq_df%>%
  filter(Target=="citrate synthase")%>%
  
  group_by(Target, life.stage, acute.treatment, conditioning.treatment)%>%
  summarise(mean=mean(delta_Cq, na.rm=TRUE), se=sd(delta_Cq, na.rm=TRUE)/sqrt(length(delta_Cq)))%>%
  
  ggplot(aes(x=acute.treatment, y=mean, colour=conditioning.treatment))+
  facet_grid(~life.stage)+
  scale_colour_manual(values=c("darkgray", "orange"))+
  geom_point()+
  geom_line(aes(group=conditioning.treatment))+
  geom_errorbar(aes(ymin=mean-se, ymax=mean+se), width=0.1)+
  ggtitle("cGAS  (sign. lifestage x acute treatment)")+
  ylab("Delta Cq")+
  ylim(-2,3)+
  geom_hline(yintercept=0, linetype="dashed")+
  theme_classic();plot6

10.3 Conclusions

10.3.1 Effects of conditioning on acute stress response

  • HSP70 and 90 genes are affected by conditioning.
  • HSP90 has significantly higher expression in treated adults than control adults at elevated temperature. No other lifestages have significant differences in expression between conditioning treatments at high temperature.
  • HSP70 has significantly lower expression in treated spat than control spat at elevated temperature. No other lifestages have significant differences between conditioning treatments at high temperature.

10.3.2 Effects of acute stress and lifestage

  • Across lifestages (except for juveniles) HSP90 decreases in expression under elevated temperature.
  • Expression of cGAS increases most dramatically in seed under elevated temperature.
  • ATP synthase and DMNT1 are not affected by elevated temperature.
  • Citrate synthase increases in expression in seed and spat under elevated temperature, but does not change in adult or juvenile stages.
  • Effects of acute treatment and life stage are just barely not significant for ATPsynthase and DMNT1. It is particularly interesting to see the trend for higher DMNT1 expression in spat at ambient temperature. There is also a trend for lower expression of ATPsynthase in seed at high temperature, but not technically significant.
LS0tCnRpdGxlOiAiMDEuMDEtcVBDUiIKYXV0aG9yOiAiU2FtIFdoaXRlIgpkYXRlOiAiMjAyNC0xMi0yMCIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGdpdGh1Yl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmxpbmstY2l0YXRpb25zOiB0cnVlCi0tLQoKIyBEZXNjcmlwdGlvbgoKVGhpcyBub3RlYm9vayBwZXJmb3JtcyBwYWlyLXdpc2UgY29tcGFyaXNvbnMgb2YgcVBDUiBnZW5lIGV4cHJlc3Npb24sIG5vcm1hbGl6ZWQgdG8gYEdBUERIYCBleHByZXNzaW9uLiBJdCBjYWxjdWxhdGVzIGRlbHRhIENxLCBkZWx0YSBkZWx0YSBDcSwgYW5kIGZvbGQgY2hhbmdlcyBpbiBleHByZXNzaW9uLiBBZGRpdGlvbmFsbHksIGl0IGdlbmVyYXRlcyBib3ggcGxvdHMgKGRlbHRhIENxKSwgYW5kIGJhciBwbG90cyAoZm9sZCBjaGFuZ2UgZXhwcmVzc2lvbikuCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShrbml0cikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dwbG90MikKCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwgICAgICAgICAjIERpc3BsYXkgY29kZSBjaHVua3MKICBldmFsID0gRkFMU0UsICAgICAgICAjIEV2YWx1YXRlIGNvZGUgY2h1bmtzCiAgd2FybmluZyA9IEZBTFNFLCAgICAgIyBIaWRlIHdhcm5pbmdzCiAgbWVzc2FnZSA9IEZBTFNFLCAgICAgIyBIaWRlIG1lc3NhZ2VzCiAgY29tbWVudCA9ICIiICAgICAgICAgIyBQcmV2ZW50cyBhcHBlbmRpbmcgJyMjJyB0byBiZWdpbm5pbmcgb2YgbGluZXMgaW4gY29kZSBvdXRwdXQKKQoKIyBHZXQgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkKY3VycmVudF9kaXIgPC0gZ2V0d2QoKQoKIyBDaGVjayBpZiB0aGUgc2NyaXB0IGlzIGJlaW5nIGtuaXR0ZWQKaWYgKGJhc2VuYW1lKGN1cnJlbnRfZGlyKSA9PSAic2NyaXB0cyIpIHsKICAjIElmIGtuaXR0aW5nLCBzZXQgdGhlIHBhdGggcmVsYXRpdmUgdG8gdGhlIHNjcmlwdCBkaXJlY3RvcnkKICBjcXNfZGlyZWN0b3J5IDwtICIuLi9kYXRhL3FQQ1IvQ3EiCn0gZWxzZSB7CiAgIyBJZiBydW5uaW5nIGludGVyYWN0aXZlbHksIHNldCB0aGUgcGF0aCByZWxhdGl2ZSB0byB0aGUgcHJvamVjdCBkaXJlY3RvcnkKICBjcXNfZGlyZWN0b3J5IDwtICJsaWZlc3RhZ2VfY2FycnlvdmVyL2RhdGEvcVBDUi9DcSIKfQpgYGAKCgojIFNldCB2YXJpYWJsZXMKCiMjIFNldCBzYW1wbGUgZ3JvdXBzCgpHcm91cHMgYXJlIG5hbWVkIGluIHRoZSBmb2xsb3dpbmcgZmFzaGlvbjoKCmA8bGlmZS5zdGFnZT4uPGNvbmRpdGlvbmluZy50cmVhdG1lbnQ+LjxhY3V0ZS50cmVhdG1lbnQ+YAoKVGhpcyBhbGxvd3MgZm9yIHBhcnNpbmcgZG93bnN0cmVhbS4KCk5PVEU6IEJlbG93IGlzIHRoZSBmdWxsIHNldCBvZiBncm91cHMgZm9yIHRoZSBfZW50aXJlIGV4cGVyaW1lbnRfLiBGb3IgdGhlIGN1cnJlbnQgcVBDUiBhbmFseXNpcywgYHNlZWRgIGFuZCBgc3BhdGAgZG8gX25vdF8gaGF2ZSBhY3V0ZSB0cmVhdG1lbnRzOyBqdXN0IGNvbmRpdGlvbmluZyB0cmVhdG1lbnRzLgoKYGBge3Igc2V0LXNhbXBsZS1ncm91cHMsIGV2YWw9VFJVRX0KCnNlZWQuY29udHJvbC5hbWJpZW50PWMoIjI5IiwgIjQwIiwgIjU1IiwgIjYzIiwgIjY5IiwgIjEwMSIsICIxMTkiLCAiMTIyIiwgIjE1NSIsICIxNjQiLCAiMTg3IiwgIjIwMiIsICIyMDkiLCAiMjE0IiwgIjIzMyIsICIyMzYiLCAiMjc1IikKc2VlZC5jb250cm9sLmhpZ2g9YygiNDIiLCAiNTkiLCAiNjAiLCAiNjIiLCAiODYiLCAiMTAyIiwgIjE0MCIsICIxNzYiLCAiMTc3IiwgIjE4NCIsICIxOTIiLCAiMjIzIiwgIjIzNCIsICIyNDMiLCAiMjQ0IiwgIjI1NCIsICIyNjQiKQpzZWVkLnRyZWF0ZWQuYW1iaWVudD1jKCIxNCIsICI0OCIsICI2NiIsICI3MiIsICI4OSIsICIxMTUiLCAiMTI5IiwgIjEzOCIsICIxNTYiLCAiMTgyIiwgIjE5MSIsICIyMDEiLCAiMjI3IiwgIjIzOSIsICIyNzAiLCAiMjc3IiwgIjI4MCIpCnNlZWQudHJlYXRlZC5oaWdoPWMoIjE1IiwgIjE5IiwgIjI0IiwgIjg4IiwgIjkyIiwgIjEwNSIsICIxMTEiLCAiMTEzIiwgIjEyMCIsICIxMjgiLCAiMTYxIiwgIjIwMCIsICIyMTEiLCAiMjU2IiwgIjI1NyIsICIyNjYiLCAiMjg1IikKc3BhdC5jb250cm9sLmFtYmllbnQ9YygiMTEiLCAiMzAiLCAiMzYiLCAiNTIiLCAiNzciLCAiMTE0IiwgIjEzNCIsICIxNDIiLCAiMTQ0IiwgIjE4MyIsICIxOTMiLCAiMjI5IiwgIjIzMCIsICIyMzEiLCAiMjQwIiwgIjI3MiIsICIyODciKQpzcGF0LmNvbnRyb2wuaGlnaD1jKCIyNyIsICI3NCIsICI5MyIsICI5NiIsICI5NyIsICIxMzciLCAiMTQzIiwgIjE1MyIsICIxNjgiLCAiMTc4IiwgIjE4OSIsICIyMDYiLCAiMjYyIiwgIjI3NCIsICIyODIiLCAiMjg0IiwgIjI4OSIpCnNwYXQudHJlYXRlZC5hbWJpZW50PWMoIjkiLCAiMTMiLCAiMzgiLCAiNDYiLCAiNDciLCAiMTIxIiwgIjE0NSIsICIxNTEiLCAiMTc0IiwgIjE5NCIsICIxOTciLCAiMTk4IiwgIjIxNiIsICIyMzUiLCAiMjQxIiwgIjI1MiIsICIyOTEiKQpzcGF0LnRyZWF0ZWQuaGlnaD1jKCI2IiwgIjI1IiwgIjUwIiwgIjc4IiwgIjEyNCIsICIxMjYiLCAiMTMxIiwgIjE2MCIsICIxNjMiLCAiMTcyIiwgIjIyMCIsICIyMjYiLCAiMjQyIiwgIjI1MyIsICIyOTYiLCAiMjk4IikKanV2ZW5pbGUuY29udHJvbC5hbWJpZW50PWMoIjE4IiwgIjU3IiwgIjY1IiwgIjc1IiwgIjc5IiwgIjEwNCIsICIxMTAiLCAiMTIzIiwgIjEyNSIsICIxNzEiLCAiMTc1IiwgIjIwNSIsICIyMzgiLCAiMjczIiwgIjI3OSIsICIyOTMiLCAiMzE3IikKanV2ZW5pbGUuY29udHJvbC5oaWdoPWMoIjEyIiwgIjM5IiwgIjQzIiwgIjQ5IiwgIjcxIiwgIjEzMCIsICIxNDEiLCAiMTQ2IiwgIjE1MCIsICIxNzAiLCAiMTk1IiwgIjI5NyIsICIzMDEiLCAiMzI0IiwgIjM1MSIsICIzNTUiLCAiMzcxIikKanV2ZW5pbGUudHJlYXRlZC5hbWJpZW50PWMoIjEiLCAiMzQiLCAiNjQiLCAiODMiLCAiOTgiLCAiMTQ3IiwgIjE1MiIsICIxNTgiLCAiMTYyIiwgIjE2OSIsICIxODgiLCAiMjcxIiwgIjI5NSIsICIzMTAiLCAiMzU3IiwgIjM2MSIsICIzODEiKQpqdXZlbmlsZS50cmVhdGVkLmhpZ2g9YygiMjgiLCAiNTMiLCAiNjEiLCAiNzMiLCAiODEiLCAiMTA2IiwgIjEwOSIsICIxMzkiLCAiMTQ5IiwgIjE3MyIsICIxODEiLCAiMjEzIiwgIjI5MCIsICIzMDIiLCAiMzExIiwgIjM2NCIsICIzOTIiKQphZHVsdC5jb250cm9sLmFtYmllbnQ9YygiMyIsICI1IiwgIjEzKiIsICIxNiIsICIxNyIsICI4MCIsICI4NyIsICI5NCIsICIxNDgiLCAiMTU5IiwgIjE3OSIsICIxODAiLCAiMjUwIiwgIjI1OCIsICIyNjgiLCAiMzEyIiwgIjMyNiIsICIzMzAiLCAiMzM0IiwgIjM0NiIsICIzNjAiLCAiMzc3IiwgIjM3OSIsICIzODYiKQphZHVsdC5jb250cm9sLmhpZ2g9YygiMjAiLCAiMjMiLCAiMjYiLCAiMzIiLCAiMzMiLCAiNjciLCAiNzAiLCAiOTAiLCAiMTA3IiwgIjEzMiIsICIxMzUiLCAiMTU3IiwgIjE2NiIsICIxODYiLCAiMjA3IiwgIjIxNSIsICIyNDgiLCAiMzE2IiwgIjM0MSIsICIzNDQiLCAiMzQ5IiwgIjM4MiIsICIzOTQiLCAiMzk1IikKYWR1bHQudHJlYXRlZC5hbWJpZW50PWMoIjciLCAiMzEiLCAiMzUiLCAiMzciLCAiNDEiLCAiNTQiLCAiODQiLCAiMTAwIiwgIjExMiIsICIxMTYiLCAiMTE4IiwgIjEzMyIsICIxNTQiLCAiMTk5IiwgIjIwMyIsICIyMDQiLCAiMjA4IiwgIjIxOSIsICIyOTQiLCAiMzE4IiwgIjMzOSIsICIzNTMiLCAiMzYzIiwgIjM3OCIpCmFkdWx0LnRyZWF0ZWQuaGlnaD1jKCIyMSIsICIyMiIsICI0NSIsICI4MiIsICI4NSIsICI5MSIsICI5NSIsICI5OSIsICIxMDMiLCAiMTA4IiwgIjExNyIsICIxMjciLCAiMTY1IiwgIjE4NSIsICIxOTAiLCAiMTk2IiwgIjIzMiIsICIyMzciLCAiMjQ1IiwgIjI2MyIsICIyNzYiLCAiMzA2IiwgIjM0MyIsICIzNzQiKQoKYGBgCgojIyBBc3NpZ24gZ3JvdXBzIHRvIGxpc3QKYGBge3IgYXNzaWduLWdyb3Vwcy10by1saXN0LCBldmFsPVRSVUV9CiMgQ29tYmluZSB2ZWN0b3JzIGludG8gbGlzdHMKIyBVc2VkIGZvciBhZGRpbmcgdHJlYXRtZW50IGluZm8gYW5kL29yIHN1YnNldHRpbmcgZG93bnN0cmVhbQoKZ3JvdXBzX2xpc3QgPC0gbGlzdChqdXZlbmlsZS5jb250cm9sLmFtYmllbnQgPSBqdXZlbmlsZS5jb250cm9sLmFtYmllbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAganV2ZW5pbGUuY29udHJvbC5oaWdoID0ganV2ZW5pbGUuY29udHJvbC5oaWdoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGp1dmVuaWxlLnRyZWF0ZWQuYW1iaWVudCA9IGp1dmVuaWxlLnRyZWF0ZWQuYW1iaWVudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBqdXZlbmlsZS50cmVhdGVkLmhpZ2ggPSBqdXZlbmlsZS50cmVhdGVkLmhpZ2gsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWR1bHQuY29udHJvbC5hbWJpZW50ID0gYWR1bHQuY29udHJvbC5hbWJpZW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkdWx0LmNvbnRyb2wuaGlnaCA9IGFkdWx0LmNvbnRyb2wuaGlnaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZHVsdC50cmVhdGVkLmFtYmllbnQgPSBhZHVsdC50cmVhdGVkLmFtYmllbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWR1bHQudHJlYXRlZC5oaWdoID0gYWR1bHQudHJlYXRlZC5oaWdoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZWQuY29udHJvbC5hbWJpZW50ID0gc2VlZC5jb250cm9sLmFtYmllbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZC5jb250cm9sLmhpZ2ggPSBzZWVkLmNvbnRyb2wuaGlnaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWVkLnRyZWF0ZWQuYW1iaWVudCA9IHNlZWQudHJlYXRlZC5hbWJpZW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZWQudHJlYXRlZC5oaWdoID0gc2VlZC50cmVhdGVkLmhpZ2gsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BhdC5jb250cm9sLmFtYmllbnQgPSBzcGF0LmNvbnRyb2wuYW1iaWVudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGF0LmNvbnRyb2wuaGlnaCA9IHNwYXQuY29udHJvbC5oaWdoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwYXQudHJlYXRlZC5hbWJpZW50ID0gc3BhdC50cmVhdGVkLmFtYmllbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BhdC50cmVhdGVkLmhpZ2ggPSBzcGF0LnRyZWF0ZWQuaGlnaCkKYGBgCgojIEZ1bmN0aW9ucwoKIyMgQ2FsY3VsYXRlIGRlbHRhIENxCgpOb3JtYWxpemVkIHRvIGRlc2lnbmF0ZWQgbm9ybWFsaXppbmcgZ2VuZQpgYGB7ciBmdW5jdGlvbi1kZWx0YS1DcSwgZXZhbD1UUlVFfQpjYWxjdWxhdGVfZGVsdGFfQ3EgPC0gZnVuY3Rpb24oZGYpIHsKICBkZiA8LSBkZiAlPiUKICAgIGdyb3VwX2J5KFNhbXBsZSkgJT4lCiAgICBtdXRhdGUoZGVsdGFfQ3EgPSBDcS5NZWFuIC0gQ3EuTWVhbltUYXJnZXQgPT0gIkdBUERIIl0pICU+JQogICAgdW5ncm91cCgpCiAgCiAgcmV0dXJuKGRmKQp9CmBgYAoKIyMgQ3JlYXRlIGRlbHRhIENxIGJveHBsb3RzCgojIyMgTGlmZXN0YWdlIGNvbXBhcmlzb24KYGBge3IgZnVuY3Rpb24tYm94cGxvdHMtZGVsdGEtQ3EsIGV2YWw9VFJVRX0KIyBGdW5jdGlvbiB0byBjcmVhdGUgYm94IHBsb3RzIGZvciBlYWNoIGNvbXBhcmlzb24KY3JlYXRlX2JveHBsb3RfZGVsdGFfQ3EgPC0gZnVuY3Rpb24oZGF0YSwgY29tcGFyaXNvbiwgdF90ZXN0X3Jlc3VsdHMpIHsKICAjIEV4dHJhY3QgbGlmZSBzdGFnZXMgZnJvbSBjb21wYXJpc29uCiAgbGlmZV9zdGFnZXMgPC0gdW5saXN0KHN0cnNwbGl0KGNvbXBhcmlzb24sICJcXC4iKSkKCiAgIyBEZWJ1Z2dpbmc6IFByaW50IGxpZmUgc3RhZ2VzCiAgIyBwcmludChwYXN0ZSgiTGlmZSBzdGFnZXMgZm9yIGNvbXBhcmlzb246IiwgY29tcGFyaXNvbikpCiAgIyBwcmludChsaWZlX3N0YWdlcykKCiAgIyBGaWx0ZXIgZGF0YSBmb3IgdGhlIHJlbGV2YW50IGxpZmUgc3RhZ2VzCiAgZmlsdGVyZWRfZGF0YSA8LSBkYXRhICU+JQogICAgZmlsdGVyKGxpZmUuc3RhZ2UgJWluJSBsaWZlX3N0YWdlcykKCiAgIyBEZWJ1Z2dpbmc6IFByaW50IGZpbHRlcmVkIGRhdGEKICAjIHByaW50KCJGaWx0ZXJlZCBkYXRhOiIpCiAgIyBwcmludChmaWx0ZXJlZF9kYXRhKQoKICAjIENoZWNrIGlmIGJvdGggbGlmZSBzdGFnZXMgYXJlIGluY2x1ZGVkCiAgaWYgKCFhbGwobGlmZV9zdGFnZXMgJWluJSB1bmlxdWUoZmlsdGVyZWRfZGF0YSRsaWZlLnN0YWdlKSkpIHsKICAgIHN0b3AoIk5vdCBhbGwgbGlmZSBzdGFnZXMgYXJlIGluY2x1ZGVkIGluIHRoZSBmaWx0ZXJlZCBkYXRhIikKICB9CgogIHlfbGltaXRzIDwtIHJhbmdlKGZpbHRlcmVkX2RhdGEkZGVsdGFfQ3EsIG5hLnJtID0gVFJVRSkKCiAgIyBEZWJ1Z2dpbmc6IFByaW50IHlfbGltaXRzCiAgIyBwcmludCgiWSBsaW1pdHM6IikKICAjIHByaW50KHlfbGltaXRzKQoKICAjIEZpbHRlciB0X3Rlc3RfcmVzdWx0cyBmb3IgdGhlIGN1cnJlbnQgY29tcGFyaXNvbgogIHRfdGVzdF9yZXN1bHRzX2ZpbHRlcmVkIDwtIHRfdGVzdF9yZXN1bHRzICU+JQogICAgZmlsdGVyKGNvbXBhcmlzb24gPT0gISFjb21wYXJpc29uKQoKICAjIERlYnVnZ2luZzogUHJpbnQgZmlsdGVyZWQgdF90ZXN0X3Jlc3VsdHMKICAjIHByaW50KCJGaWx0ZXJlZCB0X3Rlc3RfcmVzdWx0czoiKQogICMgcHJpbnQodF90ZXN0X3Jlc3VsdHNfZmlsdGVyZWQpCgogICMgRmlsdGVyIHRfdGVzdF9yZXN1bHRzIGZvciBhc3Rlcmlza3MKICB0X3Rlc3RfcmVzdWx0c193aXRoX2FzdGVyaXNrcyA8LSB0X3Rlc3RfcmVzdWx0c19maWx0ZXJlZCAlPiUKICAgIGZpbHRlcihhc3RlcmlzayAhPSAiIikKCiAgIyBEZWJ1Z2dpbmc6IFByaW50IHRfdGVzdF9yZXN1bHRzX3dpdGhfYXN0ZXJpc2tzCiAgIyBwcmludCgidF90ZXN0X3Jlc3VsdHNfd2l0aF9hc3Rlcmlza3M6IikKICAjIHByaW50KHRfdGVzdF9yZXN1bHRzX3dpdGhfYXN0ZXJpc2tzKQoKICBmb3JtYXR0ZWRfdGl0bGUgPC0gcGFzdGUwKHRvdXBwZXIoc3Vic3RyaW5nKGxpZmVfc3RhZ2VzWzFdLCAxLCAxKSksIHN1YnN0cmluZyhsaWZlX3N0YWdlc1sxXSwgMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIiB2cy4gIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3VwcGVyKHN1YnN0cmluZyhsaWZlX3N0YWdlc1syXSwgMSwgMSkpLCBzdWJzdHJpbmcobGlmZV9zdGFnZXNbMl0sIDIpKQoKICBib3hwbG90IDwtIGdncGxvdChmaWx0ZXJlZF9kYXRhLCBhZXMoeCA9IFRhcmdldCwgeSA9IGRlbHRhX0NxLCBmaWxsID0gbGlmZS5zdGFnZSkpICsKICAgIGdlb21fYm94cGxvdChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC43NSkpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyYXkiLCAic2FsbW9uIiwgImxpZ2h0Ymx1ZSIsICJsaWdodGdyZWVuIikpICsKICAgIHlsaW0oeV9saW1pdHMpICsKICAgIGxhYnMoeCA9ICJUYXJnZXQiLCB5ID0gIkRlbHRhIENxIiwgdGl0bGUgPSBmb3JtYXR0ZWRfdGl0bGUpICsKICAgICMgSGlnaGxpZ2h0ZWQgc2VjdGlvbjogQWRkcyBhc3Rlcmlza3MKICAgIGdlb21fdGV4dChkYXRhID0gdF90ZXN0X3Jlc3VsdHNfd2l0aF9hc3Rlcmlza3MsIAogICAgICAgICAgICAgIGFlcyh4ID0gVGFyZ2V0LCB5ID0geV9saW1pdHNbMl0gLSAxLCBsYWJlbCA9IGFzdGVyaXNrKSwgCiAgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBzaXplID0gOCwgY29sb3IgPSAiYmxhY2siLCBpbmhlcml0LmFlcyA9IEZBTFNFKQoKICBwcmludChib3hwbG90KQp9CmBgYAoKIyMjIENvbmRpdGlvbmluZyBjb21wYXJpc29ucwoKMS4gRXh0cmFjdCBMaWZlIFN0YWdlIGFuZCBDb25kaXRpb25pbmcgVHJlYXRtZW50czoKCi0gVGhlIGNvbXBhcmlzb24gc3RyaW5nIGlzIHNwbGl0IGludG8gaXRzIGNvbXBvbmVudHMgKGBsaWZlX3N0YWdlYCwgYHRyZWF0bWVudDFgLCBhbmQgYHRyZWF0bWVudDJgKS4KCjIuIEZpbHRlciBEYXRhOgoKLSBUaGUgZmlsdGVyZWRfZGF0YSBkYXRhIGZyYW1lIGlzIGZpbHRlcmVkIHRvIGluY2x1ZGUgb25seSB0aGUgcm93cyB3aXRoIHRoZSByZWxldmFudCBsaWZlIHN0YWdlIGFuZCBjb25kaXRpb25pbmcgdHJlYXRtZW50cy4KCjMuIENoZWNrIGZvciBCb3RoIFRyZWF0bWVudHM6CgotIEVuc3VyZSB0aGF0IGJvdGggdHJlYXRtZW50cyBhcmUgaW5jbHVkZWQgaW4gdGhlIGBmaWx0ZXJlZF9kYXRhYC4KCjQuIEZpbHRlciBULVRlc3QgUmVzdWx0czoKCi0gVGhlIGB0X3Rlc3RfcmVzdWx0c19maWx0ZXJlZGAgZGF0YSBmcmFtZSBpcyBmaWx0ZXJlZCBmb3IgdGhlIHNwZWNpZmljIGNvbXBhcmlzb24uCgotIFRoZSBgdF90ZXN0X3Jlc3VsdHNfd2l0aF9hc3Rlcmlza3NgIGRhdGEgZnJhbWUgaXMgY3JlYXRlZCB0byBpbmNsdWRlIG9ubHkgdGhlIHJvd3Mgd2l0aCBhc3Rlcmlza3MuCgo1LiBGb3JtYXQgdGhlIFRpdGxlOgoKLSBUaGUgYGZvcm1hdHRlZF90aXRsZWAgdmFyaWFibGUgaXMgY3JlYXRlZCBieSBjYXBpdGFsaXppbmcgdGhlIGZpcnN0IGxldHRlciBvZiBlYWNoIGNvbXBvbmVudCBhbmQgY29uY2F0ZW5hdGluZyB0aGVtIHdpdGggIiAtICIgYW5kICIgdnMuICIgaW4gYmV0d2Vlbi4KCi0gVGhpcyBzaG91bGQgY3JlYXRlIGJveCBwbG90cyBjb21wYXJpbmcgY29uZGl0aW9uaW5nIHRyZWF0bWVudHMgd2l0aGluIGVhY2ggbGlmZSBzdGFnZSwgd2l0aCB0aXRsZXMgZm9ybWF0dGVkIGFzIGA8bGlmZS5zdGFnZT4gLSBUcmVhdGVkIHZzLiBDb250cm9sYC4KCmBgYHtyIGZ1bmN0aW9uLWJveHBsb3RzLWRlbHRhLUNxLWNvbmRpdGlvbmluZy10cmVhdG1lbnRzLCBldmFsPVRSVUV9CiMgRnVuY3Rpb24gdG8gY3JlYXRlIGJveCBwbG90cyBmb3IgZWFjaCBjb21wYXJpc29uIG9mIGNvbmRpdGlvbmluZyB0cmVhdG1lbnRzIHdpdGhpbiBsaWZlIHN0YWdlcwpjcmVhdGVfYm94cGxvdF9jb25kaXRpb25pbmcgPC0gZnVuY3Rpb24oZGF0YSwgY29tcGFyaXNvbiwgdF90ZXN0X3Jlc3VsdHMpIHsKICAjIEV4dHJhY3QgbGlmZSBzdGFnZSBhbmQgY29uZGl0aW9uaW5nIHRyZWF0bWVudHMgZnJvbSBjb21wYXJpc29uCiAgY29tcGFyaXNvbl9wYXJ0cyA8LSB1bmxpc3Qoc3Ryc3BsaXQoY29tcGFyaXNvbiwgIlxcLiIpKQogIGxpZmVfc3RhZ2UgPC0gY29tcGFyaXNvbl9wYXJ0c1sxXQogIHRyZWF0bWVudDEgPC0gY29tcGFyaXNvbl9wYXJ0c1syXQogIHRyZWF0bWVudDIgPC0gY29tcGFyaXNvbl9wYXJ0c1szXQoKICAjIERlYnVnZ2luZzogUHJpbnQgbGlmZSBzdGFnZSBhbmQgdHJlYXRtZW50cwogICMgcHJpbnQocGFzdGUoIkxpZmUgc3RhZ2UgYW5kIHRyZWF0bWVudHMgZm9yIGNvbXBhcmlzb246IiwgY29tcGFyaXNvbikpCiAgIyBwcmludChjKGxpZmVfc3RhZ2UsIHRyZWF0bWVudDEsIHRyZWF0bWVudDIpKQoKICAjIEZpbHRlciBkYXRhIGZvciB0aGUgcmVsZXZhbnQgbGlmZSBzdGFnZSBhbmQgY29uZGl0aW9uaW5nIHRyZWF0bWVudHMKICBmaWx0ZXJlZF9kYXRhIDwtIGRhdGEgJT4lCiAgICBmaWx0ZXIobGlmZS5zdGFnZSA9PSBsaWZlX3N0YWdlLCBjb25kaXRpb25pbmcudHJlYXRtZW50ICVpbiUgYyh0cmVhdG1lbnQxLCB0cmVhdG1lbnQyKSkKCiAgIyBEZWJ1Z2dpbmc6IFByaW50IGZpbHRlcmVkIGRhdGEKICAjIHByaW50KCJGaWx0ZXJlZCBkYXRhOiIpCiAgIyBwcmludChmaWx0ZXJlZF9kYXRhKQoKICAjIENoZWNrIGlmIGJvdGggdHJlYXRtZW50cyBhcmUgaW5jbHVkZWQKICBpZiAoIWFsbChjKHRyZWF0bWVudDEsIHRyZWF0bWVudDIpICVpbiUgdW5pcXVlKGZpbHRlcmVkX2RhdGEkY29uZGl0aW9uaW5nLnRyZWF0bWVudCkpKSB7CiAgICBzdG9wKCJOb3QgYWxsIHRyZWF0bWVudHMgYXJlIGluY2x1ZGVkIGluIHRoZSBmaWx0ZXJlZCBkYXRhIikKICB9CgogIHlfbGltaXRzIDwtIHJhbmdlKGZpbHRlcmVkX2RhdGEkZGVsdGFfQ3EsIG5hLnJtID0gVFJVRSkKCiAgIyBEZWJ1Z2dpbmc6IFByaW50IHlfbGltaXRzCiAgIyBwcmludCgiWSBsaW1pdHM6IikKICAjIHByaW50KHlfbGltaXRzKQoKICAjIEZpbHRlciB0X3Rlc3RfcmVzdWx0cyBmb3IgdGhlIGN1cnJlbnQgY29tcGFyaXNvbgogIHRfdGVzdF9yZXN1bHRzX2ZpbHRlcmVkIDwtIHRfdGVzdF9yZXN1bHRzICU+JQogICAgZmlsdGVyKGNvbXBhcmlzb24gPT0gISFjb21wYXJpc29uKQoKICAjIERlYnVnZ2luZzogUHJpbnQgZmlsdGVyZWQgdF90ZXN0X3Jlc3VsdHMKICAjIHByaW50KCJGaWx0ZXJlZCB0X3Rlc3RfcmVzdWx0czoiKQogICMgcHJpbnQodF90ZXN0X3Jlc3VsdHNfZmlsdGVyZWQpCgogICMgRmlsdGVyIHRfdGVzdF9yZXN1bHRzIGZvciBhc3Rlcmlza3MKICB0X3Rlc3RfcmVzdWx0c193aXRoX2FzdGVyaXNrcyA8LSB0X3Rlc3RfcmVzdWx0c19maWx0ZXJlZCAlPiUKICAgIGZpbHRlcihhc3RlcmlzayAhPSAiIikKCiAgIyBEZWJ1Z2dpbmc6IFByaW50IHRfdGVzdF9yZXN1bHRzX3dpdGhfYXN0ZXJpc2tzCiAgIyBwcmludCgidF90ZXN0X3Jlc3VsdHNfd2l0aF9hc3Rlcmlza3M6IikKICAjIHByaW50KHRfdGVzdF9yZXN1bHRzX3dpdGhfYXN0ZXJpc2tzKQoKICAjIEZvcm1hdCB0aGUgdGl0bGUKICBmb3JtYXR0ZWRfdGl0bGUgPC0gcGFzdGUwKHRvdXBwZXIoc3Vic3RyaW5nKGxpZmVfc3RhZ2UsIDEsIDEpKSwgc3Vic3RyaW5nKGxpZmVfc3RhZ2UsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICIgLSAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdXBwZXIoc3Vic3RyaW5nKHRyZWF0bWVudDEsIDEsIDEpKSwgc3Vic3RyaW5nKHRyZWF0bWVudDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICIgdnMuICIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdG91cHBlcihzdWJzdHJpbmcodHJlYXRtZW50MiwgMSwgMSkpLCBzdWJzdHJpbmcodHJlYXRtZW50MiwgMikpCgogIGJveHBsb3QgPC0gZ2dwbG90KGZpbHRlcmVkX2RhdGEsIGFlcyh4ID0gVGFyZ2V0LCB5ID0gZGVsdGFfQ3EsIGZpbGwgPSBjb25kaXRpb25pbmcudHJlYXRtZW50KSkgKwogICAgZ2VvbV9ib3hwbG90KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjc1KSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJkYXJrZ3JheSIsICJzYWxtb24iKSkgKwogICAgeWxpbSh5X2xpbWl0cykgKwogICAgbGFicyh4ID0gIlRhcmdldCIsIHkgPSAiRGVsdGEgQ3EiLCB0aXRsZSA9IGZvcm1hdHRlZF90aXRsZSkgKwogICAgIyBIaWdobGlnaHRlZCBzZWN0aW9uOiBBZGRzIGFzdGVyaXNrcwogICAgZ2VvbV90ZXh0KGRhdGEgPSB0X3Rlc3RfcmVzdWx0c193aXRoX2FzdGVyaXNrcywgCiAgICAgICAgICAgICAgYWVzKHggPSBUYXJnZXQsIHkgPSB5X2xpbWl0c1syXSAtIDEsIGxhYmVsID0gYXN0ZXJpc2spLCAKICAgICAgICAgICAgICB2anVzdCA9IC0wLjUsIHNpemUgPSA4LCBjb2xvciA9ICJibGFjayIsIGluaGVyaXQuYWVzID0gRkFMU0UpCgogIHByaW50KGJveHBsb3QpCn0KYGBgCgojIyMgQWN1dGUgY29tcGFyaXNvbnMKCjEuIEV4dHJhY3QgTGlmZSBTdGFnZSBhbmQgQWN1dGUgVHJlYXRtZW50czoKCi0gVGhlIGNvbXBhcmlzb24gc3RyaW5nIGlzIHNwbGl0IGludG8gaXRzIGNvbXBvbmVudHMgKGBsaWZlX3N0YWdlYCwgYHRyZWF0bWVudDFgLCBhbmQgYHRyZWF0bWVudDJgKS4KCjIuIEZpbHRlciBEYXRhOgoKLSBUaGUgYGZpbHRlcmVkX2RhdGFgIGRhdGEgZnJhbWUgaXMgZmlsdGVyZWQgdG8gaW5jbHVkZSBvbmx5IHRoZSByb3dzIHdpdGggdGhlIHJlbGV2YW50IGxpZmUgc3RhZ2UgYW5kIGFjdXRlIHRyZWF0bWVudHMuCgozLiBDaGVjayBmb3IgQm90aCBUcmVhdG1lbnRzOgoKLSBFbnN1cmUgdGhhdCBib3RoIHRyZWF0bWVudHMgYXJlIGluY2x1ZGVkIGluIHRoZSBgZmlsdGVyZWRfZGF0YWAuCgo0LiBGaWx0ZXIgVC1UZXN0IFJlc3VsdHM6CgotIFRoZSBgdF90ZXN0X3Jlc3VsdHNfZmlsdGVyZWRgIGRhdGEgZnJhbWUgaXMgZmlsdGVyZWQgZm9yIHRoZSBzcGVjaWZpYyBjb21wYXJpc29uLgoKLSBUaGUgYHRfdGVzdF9yZXN1bHRzX3dpdGhfYXN0ZXJpc2tzYCBkYXRhIGZyYW1lIGlzIGNyZWF0ZWQgdG8gaW5jbHVkZSBvbmx5IHRoZSByb3dzIHdpdGggYXN0ZXJpc2tzLgpGb3JtYXQgdGhlIFRpdGxlOgoKNS4gVGhlIGZvcm1hdHRlZF90aXRsZSB2YXJpYWJsZSBpcyBjcmVhdGVkIGJ5IGNhcGl0YWxpemluZyB0aGUgZmlyc3QgbGV0dGVyIG9mIGVhY2ggY29tcG9uZW50IGFuZCBjb25jYXRlbmF0aW5nIHRoZW0gd2l0aCAiIC0gIiBhbmQgIiB2cy4gIiBpbiBiZXR3ZWVuLgotIFRoaXMgc2hvdWxkIGNyZWF0ZSBib3ggcGxvdHMgY29tcGFyaW5nIGFjdXRlIHRyZWF0bWVudHMgd2l0aGluIGVhY2ggbGlmZSBzdGFnZSwgd2l0aCB0aXRsZXMgZm9ybWF0dGVkIGFzIGA8bGlmZS5zdGFnZT4gLSBBbWJpZW50IHZzLiBIaWdoYC4KYGBge3IgZnVuY3Rpb24tYm94cGxvdHMtZGVsdGEtQ3EtdHJlYXRtZW50cywgZXZhbD1UUlVFfQoKIyBGdW5jdGlvbiB0byBjcmVhdGUgYm94IHBsb3RzIGZvciBlYWNoIGNvbXBhcmlzb24gb2YgYWN1dGUgdHJlYXRtZW50cyB3aXRoaW4gbGlmZSBzdGFnZXMKY3JlYXRlX2JveHBsb3RfYWN1dGUgPC0gZnVuY3Rpb24oZGF0YSwgY29tcGFyaXNvbiwgdF90ZXN0X3Jlc3VsdHMpIHsKICAjIEV4dHJhY3QgbGlmZSBzdGFnZSBhbmQgYWN1dGUgdHJlYXRtZW50cyBmcm9tIGNvbXBhcmlzb24KICBjb21wYXJpc29uX3BhcnRzIDwtIHVubGlzdChzdHJzcGxpdChjb21wYXJpc29uLCAiXFwuIikpCiAgbGlmZV9zdGFnZSA8LSBjb21wYXJpc29uX3BhcnRzWzFdCiAgdHJlYXRtZW50MSA8LSBjb21wYXJpc29uX3BhcnRzWzJdCiAgdHJlYXRtZW50MiA8LSBjb21wYXJpc29uX3BhcnRzWzNdCgogICMgRGVidWdnaW5nOiBQcmludCBsaWZlIHN0YWdlIGFuZCB0cmVhdG1lbnRzCiAgIyBwcmludChwYXN0ZSgiTGlmZSBzdGFnZSBhbmQgdHJlYXRtZW50cyBmb3IgY29tcGFyaXNvbjoiLCBjb21wYXJpc29uKSkKICAjIHByaW50KGMobGlmZV9zdGFnZSwgdHJlYXRtZW50MSwgdHJlYXRtZW50MikpCgogICMgRmlsdGVyIGRhdGEgZm9yIHRoZSByZWxldmFudCBsaWZlIHN0YWdlIGFuZCBhY3V0ZSB0cmVhdG1lbnRzCiAgZmlsdGVyZWRfZGF0YSA8LSBkYXRhICU+JQogICAgZmlsdGVyKGxpZmUuc3RhZ2UgPT0gbGlmZV9zdGFnZSwgYWN1dGUudHJlYXRtZW50ICVpbiUgYyh0cmVhdG1lbnQxLCB0cmVhdG1lbnQyKSkKCiAgIyBEZWJ1Z2dpbmc6IFByaW50IGZpbHRlcmVkIGRhdGEKICAjIHByaW50KCJGaWx0ZXJlZCBkYXRhOiIpCiAgIyBwcmludChmaWx0ZXJlZF9kYXRhKQoKICAjIENoZWNrIGlmIGJvdGggdHJlYXRtZW50cyBhcmUgaW5jbHVkZWQKICBpZiAoIWFsbChjKHRyZWF0bWVudDEsIHRyZWF0bWVudDIpICVpbiUgdW5pcXVlKGZpbHRlcmVkX2RhdGEkYWN1dGUudHJlYXRtZW50KSkpIHsKICAgIHN0b3AoIk5vdCBhbGwgdHJlYXRtZW50cyBhcmUgaW5jbHVkZWQgaW4gdGhlIGZpbHRlcmVkIGRhdGEiKQogIH0KCiAgeV9saW1pdHMgPC0gcmFuZ2UoZmlsdGVyZWRfZGF0YSRkZWx0YV9DcSwgbmEucm0gPSBUUlVFKQoKICAjIERlYnVnZ2luZzogUHJpbnQgeV9saW1pdHMKICAjIHByaW50KCJZIGxpbWl0czoiKQogICMgcHJpbnQoeV9saW1pdHMpCgogICMgRmlsdGVyIHRfdGVzdF9yZXN1bHRzIGZvciB0aGUgY3VycmVudCBjb21wYXJpc29uCiAgdF90ZXN0X3Jlc3VsdHNfZmlsdGVyZWQgPC0gdF90ZXN0X3Jlc3VsdHMgJT4lCiAgICBmaWx0ZXIoY29tcGFyaXNvbiA9PSAhIWNvbXBhcmlzb24pCgogICMgRGVidWdnaW5nOiBQcmludCBmaWx0ZXJlZCB0X3Rlc3RfcmVzdWx0cwogICMgcHJpbnQoIkZpbHRlcmVkIHRfdGVzdF9yZXN1bHRzOiIpCiAgIyBwcmludCh0X3Rlc3RfcmVzdWx0c19maWx0ZXJlZCkKCiAgIyBGaWx0ZXIgdF90ZXN0X3Jlc3VsdHMgZm9yIGFzdGVyaXNrcwogIHRfdGVzdF9yZXN1bHRzX3dpdGhfYXN0ZXJpc2tzIDwtIHRfdGVzdF9yZXN1bHRzX2ZpbHRlcmVkICU+JQogICAgZmlsdGVyKGFzdGVyaXNrICE9ICIiKQoKICAjIERlYnVnZ2luZzogUHJpbnQgdF90ZXN0X3Jlc3VsdHNfd2l0aF9hc3Rlcmlza3MKICAjIHByaW50KCJ0X3Rlc3RfcmVzdWx0c193aXRoX2FzdGVyaXNrczoiKQogICMgcHJpbnQodF90ZXN0X3Jlc3VsdHNfd2l0aF9hc3Rlcmlza3MpCgogICMgRm9ybWF0IHRoZSB0aXRsZQogIGZvcm1hdHRlZF90aXRsZSA8LSBwYXN0ZTAodG91cHBlcihzdWJzdHJpbmcobGlmZV9zdGFnZSwgMSwgMSkpLCBzdWJzdHJpbmcobGlmZV9zdGFnZSwgMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIiAtICIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdG91cHBlcihzdWJzdHJpbmcodHJlYXRtZW50MSwgMSwgMSkpLCBzdWJzdHJpbmcodHJlYXRtZW50MSwgMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIiB2cy4gIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3VwcGVyKHN1YnN0cmluZyh0cmVhdG1lbnQyLCAxLCAxKSksIHN1YnN0cmluZyh0cmVhdG1lbnQyLCAyKSkKCiAgYm94cGxvdCA8LSBnZ3Bsb3QoZmlsdGVyZWRfZGF0YSwgYWVzKHggPSBUYXJnZXQsIHkgPSBkZWx0YV9DcSwgZmlsbCA9IGFjdXRlLnRyZWF0bWVudCkpICsKICAgIGdlb21fYm94cGxvdChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC43NSkpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyYXkiLCAic2FsbW9uIikpICsKICAgIHlsaW0oeV9saW1pdHMpICsKICAgIGxhYnMoeCA9ICJUYXJnZXQiLCB5ID0gIkRlbHRhIENxIiwgdGl0bGUgPSBmb3JtYXR0ZWRfdGl0bGUpICsKICAgICMgSGlnaGxpZ2h0ZWQgc2VjdGlvbjogQWRkcyBhc3Rlcmlza3MKICAgIGdlb21fdGV4dChkYXRhID0gdF90ZXN0X3Jlc3VsdHNfd2l0aF9hc3Rlcmlza3MsIAogICAgICAgICAgICAgIGFlcyh4ID0gVGFyZ2V0LCB5ID0geV9saW1pdHNbMl0gLSAxLCBsYWJlbCA9IGFzdGVyaXNrKSwgCiAgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBzaXplID0gOCwgY29sb3IgPSAibWFnZW50YSIsIGluaGVyaXQuYWVzID0gRkFMU0UpCgogIHByaW50KGJveHBsb3QpCn0KYGBgCgojIyMgQWN1dGUgdHJlYXRlbWVudHMgd2l0aGluIGxpZmUgc3RhZ2UgY29uZGl0aW9uaW5nCmBgYHtyIGZ1bmN0aW9uLWJveHBsb3RzLWRlbHRhLUNxLWFjdXRlLXRyZWF0bWVudHMtd2l0aGluLWxpZmVzdGFnZS1jb25kaXRpb25pbmcsIGV2YWw9VFJVRX0KIyBGdW5jdGlvbiB0byBjcmVhdGUgYm94IHBsb3RzIGZvciBlYWNoIGNvbXBhcmlzb24gb2YgYWN1dGUgdHJlYXRtZW50cyB3aXRoaW4gbGlmZSBzdGFnZXMgYW5kIGNvbmRpdGlvbmluZyB0cmVhdG1lbnRzCmNyZWF0ZV9ib3hwbG90X2FjdXRlX2NvbmRpdGlvbmluZyA8LSBmdW5jdGlvbihkYXRhLCBjb21wYXJpc29uLCB0X3Rlc3RfcmVzdWx0cykgewogICMgRXh0cmFjdCBsaWZlIHN0YWdlLCBjb25kaXRpb25pbmcgdHJlYXRtZW50LCBhbmQgYWN1dGUgdHJlYXRtZW50cyBmcm9tIGNvbXBhcmlzb24KICBjb21wYXJpc29uX3BhcnRzIDwtIHVubGlzdChzdHJzcGxpdChjb21wYXJpc29uLCAiXFwuIikpCiAgbGlmZV9zdGFnZSA8LSBjb21wYXJpc29uX3BhcnRzWzFdCiAgY29uZGl0aW9uaW5nX3RyZWF0bWVudCA8LSBjb21wYXJpc29uX3BhcnRzWzJdCiAgdHJlYXRtZW50MSA8LSBjb21wYXJpc29uX3BhcnRzWzNdCiAgdHJlYXRtZW50MiA8LSBjb21wYXJpc29uX3BhcnRzWzVdCgogICMgRmlsdGVyIGRhdGEgZm9yIHRoZSByZWxldmFudCBsaWZlIHN0YWdlLCBjb25kaXRpb25pbmcgdHJlYXRtZW50LCBhbmQgYWN1dGUgdHJlYXRtZW50cwogIGZpbHRlcmVkX2RhdGEgPC0gZGF0YSAlPiUKICAgIGZpbHRlcihsaWZlLnN0YWdlID09IGxpZmVfc3RhZ2UsIGNvbmRpdGlvbmluZy50cmVhdG1lbnQgPT0gY29uZGl0aW9uaW5nX3RyZWF0bWVudCwgYWN1dGUudHJlYXRtZW50ICVpbiUgYyh0cmVhdG1lbnQxLCB0cmVhdG1lbnQyKSkKCiAgIyBDaGVjayBpZiBib3RoIHRyZWF0bWVudHMgYXJlIGluY2x1ZGVkCiAgaWYgKCFhbGwoYyh0cmVhdG1lbnQxLCB0cmVhdG1lbnQyKSAlaW4lIHVuaXF1ZShmaWx0ZXJlZF9kYXRhJGFjdXRlLnRyZWF0bWVudCkpKSB7CiAgICBzdG9wKCJOb3QgYWxsIHRyZWF0bWVudHMgYXJlIGluY2x1ZGVkIGluIHRoZSBmaWx0ZXJlZCBkYXRhIikKICB9CgogIHlfbGltaXRzIDwtIHJhbmdlKGZpbHRlcmVkX2RhdGEkZGVsdGFfQ3EsIG5hLnJtID0gVFJVRSkKCiAgIyBGaWx0ZXIgdF90ZXN0X3Jlc3VsdHMgZm9yIHRoZSBjdXJyZW50IGNvbXBhcmlzb24KICB0X3Rlc3RfcmVzdWx0c19maWx0ZXJlZCA8LSB0X3Rlc3RfcmVzdWx0cyAlPiUKICAgIGZpbHRlcihjb21wYXJpc29uID09ICEhY29tcGFyaXNvbikKCiAgIyBGaWx0ZXIgdF90ZXN0X3Jlc3VsdHMgZm9yIGFzdGVyaXNrcwogIHRfdGVzdF9yZXN1bHRzX3dpdGhfYXN0ZXJpc2tzIDwtIHRfdGVzdF9yZXN1bHRzX2ZpbHRlcmVkICU+JQogICAgZmlsdGVyKGFzdGVyaXNrICE9ICIiKQoKICAjIEZvcm1hdCB0aGUgdGl0bGUKICBmb3JtYXR0ZWRfdGl0bGUgPC0gcGFzdGUwKHRvdXBwZXIoc3Vic3RyaW5nKGxpZmVfc3RhZ2UsIDEsIDEpKSwgc3Vic3RyaW5nKGxpZmVfc3RhZ2UsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICIgLSAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdXBwZXIoc3Vic3RyaW5nKGNvbmRpdGlvbmluZ190cmVhdG1lbnQsIDEsIDEpKSwgc3Vic3RyaW5nKGNvbmRpdGlvbmluZ190cmVhdG1lbnQsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICIgLSAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdXBwZXIoc3Vic3RyaW5nKHRyZWF0bWVudDEsIDEsIDEpKSwgc3Vic3RyaW5nKHRyZWF0bWVudDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICIgdnMuICIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdG91cHBlcihzdWJzdHJpbmcodHJlYXRtZW50MiwgMSwgMSkpLCBzdWJzdHJpbmcodHJlYXRtZW50MiwgMikpCgogIGJveHBsb3QgPC0gZ2dwbG90KGZpbHRlcmVkX2RhdGEsIGFlcyh4ID0gVGFyZ2V0LCB5ID0gZGVsdGFfQ3EsIGZpbGwgPSBhY3V0ZS50cmVhdG1lbnQpKSArCiAgICBnZW9tX2JveHBsb3QocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNzUpKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImRhcmtncmF5IiwgInNhbG1vbiIpKSArCiAgICB5bGltKHlfbGltaXRzKSArCiAgICBsYWJzKHggPSAiVGFyZ2V0IiwgeSA9ICJEZWx0YSBDcSIsIHRpdGxlID0gZm9ybWF0dGVkX3RpdGxlKSArCiAgICAjIEFkZHMgYXN0ZXJpc2tzCiAgICBnZW9tX3RleHQoZGF0YSA9IHRfdGVzdF9yZXN1bHRzX3dpdGhfYXN0ZXJpc2tzLCAKICAgICAgICAgICAgICBhZXMoeCA9IFRhcmdldCwgeSA9IHlfbGltaXRzWzJdIC0gMSwgbGFiZWwgPSBhc3RlcmlzayksIAogICAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDgsIGNvbG9yID0gImJsYWNrIiwgaW5oZXJpdC5hZXMgPSBGQUxTRSkKCiAgcHJpbnQoYm94cGxvdCkKfQpgYGAKCiMgUmVhZCBpbiBmaWxlcwpgYGB7ciByZWFkLWluLUNxLWZpbGVzLCBldmFsPVRSVUV9CgojIEdldCBhIGxpc3Qgb2YgYWxsIENTViBmaWxlcyBpbiB0aGUgZGlyZWN0b3J5IHdpdGggdGhlIG5hbWluZyBzdHJ1Y3R1cmUgIipDcS1SZXN1bHRzLmNzdiIKY3FfZmlsZV9saXN0IDwtIGxpc3QoKSAjIEluaXRpYWxpemUgbGlzdApjcV9maWxlX2xpc3QgPC0gbGlzdC5maWxlcyhwYXRoID0gY3FzX2RpcmVjdG9yeSwgcGF0dGVybiA9ICJDcS1SZXN1bHRzXFwuY3N2JCIsIGZ1bGwubmFtZXMgPSBUUlVFKQoKIyBJbml0aWFsaXplIGFuIGVtcHR5IGxpc3QgdG8gc3RvcmUgdGhlIGRhdGEgZnJhbWVzCmRhdGFfZnJhbWVzX2xpc3QgPC0gbGlzdCgpCgojIExvb3AgdGhyb3VnaCBlYWNoIGZpbGUgYW5kIHJlYWQgaXQgaW50byBhIGRhdGEgZnJhbWUsIHRoZW4gYWRkIGl0IHRvIHRoZSBsaXN0CmZvciAoZmlsZSBpbiBjcV9maWxlX2xpc3QpIHsKICBkYXRhIDwtIHJlYWQuY3N2KGZpbGUsIGhlYWRlciA9IFRSVUUpCiAgZGF0YSRTYW1wbGUgPC0gYXMuY2hhcmFjdGVyKGRhdGEkU2FtcGxlKSAgIyBDb252ZXJ0IFNhbXBsZSBjb2x1bW4gdG8gY2hhcmFjdGVyIHR5cGUKICBkYXRhX2ZyYW1lc19saXN0W1tmaWxlXV0gPC0gZGF0YQp9CgojIENvbWJpbmUgYWxsIGRhdGEgZnJhbWVzIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZQpjb21iaW5lZF9kZiA8LSBiaW5kX3Jvd3MoZGF0YV9mcmFtZXNfbGlzdCwgLmlkID0gImRhdGFfZnJhbWVfaWQiKQoKc3RyKGNvbWJpbmVkX2RmKQoKYGBgCgojIENsZWFuIGRhdGEKCgojIyBSZXBsYWNlIHRhcmdldCBuYW1lcwpgYGB7ciByZXBsYWNlLXRhcmdldC1uYW1lcywgZXZhbD1UUlVFfQojIFJlbW92ZSByb3dzIHdpdGggU2FtcGxlIG5hbWUgIk5UQyIKY29tYmluZWRfZGYgPC0gY29tYmluZWRfZGZbY29tYmluZWRfZGYkU2FtcGxlICE9ICJOVEMiLCBdCgoKIyBSZXBsYWNlIHZhbHVlcyBpbiB0aGUgVGFyZ2V0IGNvbHVtbgpjb21iaW5lZF9kZiRUYXJnZXQgPC0gZ3N1YigiQ2dfR0FQREhfMjA1X0YtMzU1X1IgXFwoU1IgSURzOiAxMTcyLzNcXCkiLCAiR0FQREgiLCBjb21iaW5lZF9kZiRUYXJnZXQpCgpjb21iaW5lZF9kZiRUYXJnZXQgPC0gZ3N1YigiQ2dfQVRQc3ludGhhc2VfRi9SIFxcKFNSIElEczogMTM4NS82XFwpIiwgIkFUUHN5bnRoYXNlIiwgY29tYmluZWRfZGYkVGFyZ2V0KQoKY29tYmluZWRfZGYkVGFyZ2V0IDwtIGdzdWIoIkNnX2NHQVMgXFwoU1IgSURzOiAxODI2LzdcXCkiLCAiY0dBUyIsIGNvbWJpbmVkX2RmJFRhcmdldCkKCmNvbWJpbmVkX2RmJFRhcmdldCA8LSBnc3ViKCJDZ19jaXRyYXRlX3N5bnRoYXNlIFxcKFNSIElEczogMTM4My80XFwpIiwgImNpdHJhdGUgc3ludGhhc2UiLCBjb21iaW5lZF9kZiRUYXJnZXQpCgpjb21iaW5lZF9kZiRUYXJnZXQgPC0gZ3N1YigiQ2dfRE5NVDFfRiBcXChTUiBJRHM6IDE1MTAvMVxcKSIsICJETk1UMSIsIGNvbWJpbmVkX2RmJFRhcmdldCkKCmNvbWJpbmVkX2RmJFRhcmdldCA8LSBnc3ViKCJDZ19IU1A3MF9GL1IgXFwoU1IgSURzOiA1OTgvOVxcKSIsICJIU1A3MCIsIGNvbWJpbmVkX2RmJFRhcmdldCkKCmNvbWJpbmVkX2RmJFRhcmdldCA8LSBnc3ViKCJDZ19Ic3A5MF9GL1IgXFwoU1IgSURzOiAxNTMyLzNcXCkiLCAiSFNQOTAiLCBjb21iaW5lZF9kZiRUYXJnZXQpCgpjb21iaW5lZF9kZiRUYXJnZXQgPC0gZ3N1YigiQ2dfVklQRVJJTl9GL1IgXFwoU1IgSURzOiAxODI4LzlcXCkiLCAidmlwZXJpbiIsIGNvbWJpbmVkX2RmJFRhcmdldCkKCnN0cihjb21iaW5lZF9kZikKCmxldmVscyhhcy5mYWN0b3IoY29tYmluZWRfZGYkVGFyZ2V0KSkKYGBgCgojIyBJZGVudGlmeSBTYW1wbGVzIHdpdGggQ3EuU3RkLi5EZXYgPiAwLjUKYGBge3IgaGlnaC1jcS1zdGQtZGV2LCBldmFsPVRSVUV9CiMgRmlsdGVyIG91dCByb3dzIHdoZXJlIENxLlN0ZC4uRGV2IGlzIE5BCmNvbWJpbmVkX2RmIDwtIGNvbWJpbmVkX2RmWyFpcy5uYShjb21iaW5lZF9kZiRDcS5TdGQuLkRldiksIF0KCiMgRmlsdGVyIHJvd3Mgd2hlcmUgQ3EuU3RkLi5EZXYgaXMgZ3JlYXRlciB0aGFuIDAuNQpoaWdoX2NxX3N0ZF9kZXYgPC0gY29tYmluZWRfZGZbY29tYmluZWRfZGYkQ3EuU3RkLi5EZXYgPiAwLjUsIF0KCiMgUHJpbnQgdGhlIGZpbHRlcmVkIHJvd3Mgd2l0aCBzcGVjaWZpZWQgY29sdW1ucywgd2l0aG91dCByb3cgbmFtZXMKcHJpbnQoaGlnaF9jcV9zdGRfZGV2WywgYygiVGFyZ2V0IiwgIlNhbXBsZSIsICJDcSIsICJDcS5TdGQuLkRldiIpXSwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMgUmVtb3ZlIGJhZCB0ZWNobmljYWwgcmVwcwpgYGB7ciBhZHVsdC1qdXYtcmVtb3ZlLWJhZC10ZWNobmljYWwtcmVwcywgZXZhbD1UUlVFfQojIEdyb3VwIGJ5IFNhbXBsZSBhbmQgVGFyZ2V0LCB0aGVuIGZpbHRlciBvdXQgdGhlIG91dGxpZXIgcmVwbGljYXRlCmNvbWJpbmVkLmZpdGVyZWRfZGY8LSBjb21iaW5lZF9kZiAlPiUKICBncm91cF9ieShTYW1wbGUsIFRhcmdldCkgJT4lCiAgZmlsdGVyKGFicyhDcSAtIG1lYW4oQ3EsIG5hLnJtID0gVFJVRSkpIDw9IENxLlN0ZC4uRGV2KQoKIyBQcmludCB0aGUgZmlsdGVyZWQgZGF0YSBmcmFtZQpzdHIoY29tYmluZWQuZml0ZXJlZF9kZikKYGBgCgoKCiMgR3JvdXAgc2FtcGxlcyBieSB0YXJnZXQKYGBge3Igc2FtcGxlcy1ieS10YXJnZXQsIGV2YWw9VFJVRX0KIyBHcm91cCBieSBTYW1wbGUgYW5kIFRhcmdldCwgdGhlbiBzdW1tYXJpemUgdG8gZ2V0IHVuaXF1ZSByb3dzIGZvciBlYWNoIHNhbXBsZQpncm91cGVkX2RmIDwtIGNvbWJpbmVkLmZpdGVyZWRfZGYlPiUKICBncm91cF9ieShTYW1wbGUsIFRhcmdldCkgJT4lCiAgc3VtbWFyaXplKENxLk1lYW4gPSBtZWFuKENxLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkKCnN0cihncm91cGVkX2RmKQpgYGAKCiMgQWRkIGxpZmUgc3RhZ2UgYW5kIHRyZWF0bWVudCBjb2xzCmBgYHtyIGFkZC1jb2x1bW5zLCBldmFsPVRSVUV9CiMgSW5pdGlhbGl6ZSBuZXcgY29sdW1ucwpncm91cGVkX2RmIDwtIGdyb3VwZWRfZGYgJT4lCiAgbXV0YXRlKGxpZmUuc3RhZ2UgPSBOQV9jaGFyYWN0ZXJfLAogICAgICAgICBjb25kaXRpb25pbmcudHJlYXRtZW50ID0gTkFfY2hhcmFjdGVyXywKICAgICAgICAgYWN1dGUudHJlYXRtZW50ID0gTkFfY2hhcmFjdGVyXykKCiMgTG9vcCB0aHJvdWdoIGVhY2ggdmVjdG9yCmZvciAodmVjX25hbWUgaW4gbmFtZXMoZ3JvdXBzX2xpc3QpKSB7CiAgdmVjIDwtIGdyb3Vwc19saXN0W1t2ZWNfbmFtZV1dCiAgc3RhZ2UgPC0gc3Ryc3BsaXQodmVjX25hbWUsICJcXC4iKVtbMV1dWzFdCiAgY29uZGl0aW9uaW5nX3RyZWF0bWVudCA8LSBzdHJzcGxpdCh2ZWNfbmFtZSwgIlxcLiIpW1sxXV1bMl0KICBhY3V0ZV90cmVhdG1lbnQgPC0gc3Ryc3BsaXQodmVjX25hbWUsICJcXC4iKVtbMV1dWzNdCiAgCiAgIyBMb29wIHRocm91Z2ggZWFjaCByb3cgaW4gZ3JvdXBlZF9kZgogIGZvciAoaSBpbiAxOm5yb3coZ3JvdXBlZF9kZikpIHsKICAgIHNhbXBsZSA8LSBncm91cGVkX2RmJFNhbXBsZVtpXQogICAgCiAgICAjIENoZWNrIGlmIHNhbXBsZSBpcyBpbiB0aGUgdmVjdG9yCiAgICBpZiAoc2FtcGxlICVpbiUgdmVjKSB7CiAgICAgICMgVXBkYXRlIGxpZmUuc3RhZ2UgYW5kIHRyZWF0bWVudCBjb2x1bW5zCiAgICAgIGdyb3VwZWRfZGYkbGlmZS5zdGFnZVtpXSA8LSBzdGFnZQogICAgICBncm91cGVkX2RmJGNvbmRpdGlvbmluZy50cmVhdG1lbnRbaV0gPC0gY29uZGl0aW9uaW5nX3RyZWF0bWVudAogICAgICBncm91cGVkX2RmJGFjdXRlLnRyZWF0bWVudFtpXSA8LWFjdXRlX3RyZWF0bWVudAogICAgfQogIH0KfQoKc3RyKGdyb3VwZWRfZGYpCgpgYGAKCiMgRGVsdGEgQ3EgdG8gTm9ybWFsaXppbmcgR2VuZQpgYGB7ciBkZWx0YS1DcSwgZXZhbD1UUlVFfQojIENhbGN1bGF0ZSBkZWx0YSBDcSBieSBzdWJ0cmFjdGluZyBHQVBESCBDcS5NZWFuIGZyb20gZWFjaCBjb3JyZXNwb25kaW5nIFNhbXBsZSBDcS5NZWFuCmRlbHRhX0NxX2RmIDwtIGNhbGN1bGF0ZV9kZWx0YV9DcShncm91cGVkX2RmKQoKIyBGaWx0ZXJzIG91dCBub3JtYWxpemluZyBnZW5lLCBzaW5jZSBubyBuZWVkIHRvIGNvbXBhcmUgbm9ybWFsaXppbmcgZ2VuZSB0byBpdHNlbGYuCmRlbHRhX0NxX2RmIDwtIGRlbHRhX0NxX2RmICU+JQogIGZpbHRlcighaXMubmEobGlmZS5zdGFnZSksICFpcy5uYShUYXJnZXQpLCBUYXJnZXQgIT0gIkdBUERIIikKCnN0cihkZWx0YV9DcV9kZikKYGBgCgojIyB0LXRlc3RzCgojIyMgTGlmZSBTdGFnZXMKClRoaXMgY29kZSBkb2VzIHRoZSBmb2xsb3dpbmc6CgoxLiBFeHRyYWN0cyB0aGUgdW5pcXVlIGxpZmUuc3RhZ2UgbGV2ZWxzIGZyb20gdGhlIGRhdGEgZnJhbWUuCjIuIEdlbmVyYXRlcyBhbGwgcG9zc2libGUgcGFpcnMgb2YgbGlmZS5zdGFnZSBsZXZlbHMgdXNpbmcgdGhlIGNvbWJuIGZ1bmN0aW9uLgozLiBJdGVyYXRlcyBvdmVyIGVhY2ggcGFpciBhbmQgcGVyZm9ybXMgdGhlIHQtdGVzdCBmb3IgZWFjaCBUYXJnZXQuIEFkZHMgYW4KYXN0ZXJpc2sgY29sdW1uIGFuZCBhbiBhc3RlcmlzayBpZiB0aGUgcC12YWx1ZSBpcyA8PSAwLjA1LiBVc2VmdWwgZm9yIGRvd25zdHJlYW0KcGFyc2luZy4KNC4gU3RvcmVzIHRoZSByZXN1bHRzIGluIGEgbGlzdCBhbmQgY29tYmluZXMgdGhlbSBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUuCjUuIEFkZHMgYSBjb21wYXJpc29uIGNvbHVtbiB0byBpbmRpY2F0ZSB3aGljaCBsaWZlLnN0YWdlIGxldmVscyB3ZXJlIGNvbXBhcmVkLgoKYGBge3IgbGlmZS1zdGFnZS10LXRlc3RzLCBldmFsPVRSVUV9CiMgRXh0cmFjdCB1bmlxdWUgbGlmZS5zdGFnZSBsZXZlbHMKdW5pcXVlX2xpZmVfc3RhZ2VzIDwtIHVuaXF1ZShkZWx0YV9DcV9kZiRsaWZlLnN0YWdlKQoKIyBHZW5lcmF0ZSBhbGwgcG9zc2libGUgcGFpcnMgb2YgbGlmZS5zdGFnZSBsZXZlbHMKbGlmZV9zdGFnZV9wYWlycyA8LSBjb21ibih1bmlxdWVfbGlmZV9zdGFnZXMsIDIsIHNpbXBsaWZ5ID0gRkFMU0UpCgojIEluaXRpYWxpemUgYSBsaXN0IHRvIHN0b3JlIHJlc3VsdHMKbGlmZV9zdGFnZV90X3Rlc3RfcmVzdWx0c19saXN0IDwtIGxpc3QoKQoKZm9yIChwYWlyIGluIGxpZmVfc3RhZ2VfcGFpcnMpIHsKICBzdGFnZTEgPC0gcGFpclsxXQogIHN0YWdlMiA8LSBwYWlyWzJdCiAgCiAgIyBQZXJmb3JtIHQtdGVzdCBmb3IgZWFjaCBUYXJnZXQgY29tcGFyaW5nIHRoZSB0d28gbGlmZS5zdGFnZSBsZXZlbHMKICB0X3Rlc3RfcmVzdWx0cyA8LSBkZWx0YV9DcV9kZiAlPiUKICAgIGZpbHRlcihsaWZlLnN0YWdlICVpbiUgYyhzdGFnZTEsIHN0YWdlMikpICU+JQogICAgZ3JvdXBfYnkoVGFyZ2V0KSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgdF90ZXN0X3Jlc3VsdCA9IGxpc3QodC50ZXN0KGRlbHRhX0NxIH4gbGlmZS5zdGFnZSkpCiAgICApICU+JQogICAgdW5ncm91cCgpICU+JQogICAgbXV0YXRlKAogICAgICBlc3RpbWF0ZV9kaWZmID0gc2FwcGx5KHRfdGVzdF9yZXN1bHQsIGZ1bmN0aW9uKHgpIHgkZXN0aW1hdGVbMV0gLSB4JGVzdGltYXRlWzJdKSwKICAgICAgcF92YWx1ZSA9IHNhcHBseSh0X3Rlc3RfcmVzdWx0LCBmdW5jdGlvbih4KSB4JHAudmFsdWUpLAogICAgICBhc3RlcmlzayA9IGlmZWxzZShwX3ZhbHVlIDw9IDAuMDUsICIqIiwgIiIpLCAjIEFkZHMgYXN0ZXJpc2sgY29sdW1uIGFuZCBhc3RlcmlzayBmb3IgcC12YWx1ZS4KICAgICAgY29tcGFyaXNvbiA9IHBhc3RlKHN0YWdlMSwgInZzIiwgc3RhZ2UyLCBzZXAgPSAiLiIpCiAgICApICU+JQogICAgc2VsZWN0KCF0X3Rlc3RfcmVzdWx0KQogIAogIGxpZmVfc3RhZ2VfdF90ZXN0X3Jlc3VsdHNfbGlzdFtbcGFzdGUoc3RhZ2UxLCBzdGFnZTIsIHNlcCA9ICIuIildXSA8LSB0X3Rlc3RfcmVzdWx0cwp9CgojIENvbWJpbmUgcmVzdWx0cyBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUKbGlmZV9zdGFnZV90X3Rlc3RfcmVzdWx0c19kZiA8LSBiaW5kX3Jvd3MobGlmZV9zdGFnZV90X3Rlc3RfcmVzdWx0c19saXN0LCAuaWQgPSAiY29tcGFyaXNvbiIpCgojIFZpZXcgdGhlIHJlc3VsdHMKcHJpbnQobGlmZV9zdGFnZV90X3Rlc3RfcmVzdWx0c19kZikKYGBgCgojIyMgQ29uZGl0aW9uaW5nIHRyZWF0bWVudHMKClRoaXMgY29kZSBkb2VzIHRoZSBmb2xsb3dpbmc6CgoxLiBFeHRyYWN0cyB0aGUgdW5pcXVlIGxpZmUuc3RhZ2UgbGV2ZWxzIGZyb20gdGhlIGRhdGEgZnJhbWUuCjIuIEZvciBlYWNoIGxpZmUuc3RhZ2UsIGV4dHJhY3RzIHRoZSB1bmlxdWUgY29uZGl0aW9uaW5nLnRyZWF0bWVudCBsZXZlbHMuCjMuIEdlbmVyYXRlcyBhbGwgcG9zc2libGUgcGFpcnMgb2YgY29uZGl0aW9uaW5nLnRyZWF0bWVudCBsZXZlbHMgd2l0aGluIGVhY2ggbGlmZS5zdGFnZS4KNC4gSXRlcmF0ZXMgb3ZlciBlYWNoIHBhaXIgYW5kIHBlcmZvcm1zIHRoZSB0LXRlc3QgZm9yIGVhY2ggVGFyZ2V0LiBBZGRzIGFuCmFzdGVyaXNrIGNvbHVtbiBhbmQgYW4gYXN0ZXJpc2sgaWYgdGhlIHAtdmFsdWUgaXMgPD0gMC4wNS4gVXNlZnVsIGZvciBkb3duc3RyZWFtCnBhcnNpbmcuCjUuIFN0b3JlcyB0aGUgcmVzdWx0cyBpbiBhIGxpc3QgYW5kIGNvbWJpbmVzIHRoZW0gaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lLgo2LiBBZGRzIGEgY29tcGFyaXNvbiBjb2x1bW4gdG8gaW5kaWNhdGUgd2hpY2ggbGlmZS5zdGFnZSBhbmQgY29uZGl0aW9uaW5nLnRyZWF0bWVudCBsZXZlbHMgd2VyZSBjb21wYXJlZC4KCmBgYHtyIGNvbmRpdGlvbmluZy10cmVhdG1lbnRzLWxpZmUtc3RhZ2VzLCBldmFsPVRSVUV9CiMgRXh0cmFjdCB1bmlxdWUgbGlmZS5zdGFnZSBsZXZlbHMKdW5pcXVlX2xpZmVfc3RhZ2VzIDwtIHVuaXF1ZShkZWx0YV9DcV9kZiRsaWZlLnN0YWdlKQoKIyBJbml0aWFsaXplIGEgbGlzdCB0byBzdG9yZSByZXN1bHRzCmNvbmRpdGlvbmluZ190cmVhdG1lbnRfdF90ZXN0X3Jlc3VsdHNfbGlzdCA8LSBsaXN0KCkKCmZvciAoc3RhZ2UgaW4gdW5pcXVlX2xpZmVfc3RhZ2VzKSB7CiAgIyBFeHRyYWN0IHVuaXF1ZSBjb25kaXRpb25pbmcudHJlYXRtZW50IGxldmVscyB3aXRoaW4gdGhlIGN1cnJlbnQgbGlmZS5zdGFnZQogIHVuaXF1ZV90cmVhdG1lbnRzIDwtIHVuaXF1ZShkZWx0YV9DcV9kZiAlPiUgZmlsdGVyKGxpZmUuc3RhZ2UgPT0gc3RhZ2UpICU+JSBwdWxsKGNvbmRpdGlvbmluZy50cmVhdG1lbnQpKQogIAogICMgR2VuZXJhdGUgYWxsIHBvc3NpYmxlIHBhaXJzIG9mIGNvbmRpdGlvbmluZy50cmVhdG1lbnQgbGV2ZWxzCiAgdHJlYXRtZW50X3BhaXJzIDwtIGNvbWJuKHVuaXF1ZV90cmVhdG1lbnRzLCAyLCBzaW1wbGlmeSA9IEZBTFNFKQogIAogIGZvciAocGFpciBpbiB0cmVhdG1lbnRfcGFpcnMpIHsKICAgIHRyZWF0bWVudDEgPC0gcGFpclsxXQogICAgdHJlYXRtZW50MiA8LSBwYWlyWzJdCiAgICAKICAgICMgUGVyZm9ybSB0LXRlc3QgZm9yIGVhY2ggVGFyZ2V0IGNvbXBhcmluZyB0aGUgdHdvIGNvbmRpdGlvbmluZy50cmVhdG1lbnQgbGV2ZWxzIHdpdGhpbiB0aGUgY3VycmVudCBsaWZlLnN0YWdlCiAgICB0X3Rlc3RfcmVzdWx0cyA8LSBkZWx0YV9DcV9kZiAlPiUKICAgICAgZmlsdGVyKGxpZmUuc3RhZ2UgPT0gc3RhZ2UsIGNvbmRpdGlvbmluZy50cmVhdG1lbnQgJWluJSBjKHRyZWF0bWVudDEsIHRyZWF0bWVudDIpKSAlPiUKICAgICAgZ3JvdXBfYnkoVGFyZ2V0KSAlPiUKICAgICAgc3VtbWFyaXNlKAogICAgICAgIHRfdGVzdF9yZXN1bHQgPSBsaXN0KHQudGVzdChkZWx0YV9DcSB+IGNvbmRpdGlvbmluZy50cmVhdG1lbnQpKQogICAgICApICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBlc3RpbWF0ZV9kaWZmID0gc2FwcGx5KHRfdGVzdF9yZXN1bHQsIGZ1bmN0aW9uKHgpIHgkZXN0aW1hdGVbMV0gLSB4JGVzdGltYXRlWzJdKSwKICAgICAgICBwX3ZhbHVlID0gc2FwcGx5KHRfdGVzdF9yZXN1bHQsIGZ1bmN0aW9uKHgpIHgkcC52YWx1ZSksCiAgICAgICAgYXN0ZXJpc2sgPSBpZmVsc2UocF92YWx1ZSA8PSAwLjA1LCAiKiIsICIiKSwgIyBBZGRzIGFzdGVyaXNrIGNvbHVtbiBhbmQgYXN0ZXJpc2sgZm9yIHAtdmFsdWUuCiAgICAgICAgY29tcGFyaXNvbiA9IHBhc3RlKHN0YWdlLCB0cmVhdG1lbnQxLCAidnMiLCB0cmVhdG1lbnQyLCBzZXAgPSAiLiIpCiAgICAgICkgJT4lCiAgICAgIHNlbGVjdCghdF90ZXN0X3Jlc3VsdCkKICAgIAogICAgY29uZGl0aW9uaW5nX3RyZWF0bWVudF90X3Rlc3RfcmVzdWx0c19saXN0W1twYXN0ZShzdGFnZSwgdHJlYXRtZW50MSwgdHJlYXRtZW50Miwgc2VwID0gIi4iKV1dIDwtIHRfdGVzdF9yZXN1bHRzCiAgfQp9CgojIENvbWJpbmUgcmVzdWx0cyBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUKY29uZGl0aW9uaW5nX3RyZWF0bWVudF90X3Rlc3RfcmVzdWx0c19kZiA8LSBiaW5kX3Jvd3MoY29uZGl0aW9uaW5nX3RyZWF0bWVudF90X3Rlc3RfcmVzdWx0c19saXN0LCAuaWQgPSAiY29tcGFyaXNvbiIpCgojIFZpZXcgdGhlIHJlc3VsdHMKcHJpbnQoY29uZGl0aW9uaW5nX3RyZWF0bWVudF90X3Rlc3RfcmVzdWx0c19kZikKYGBgCgoKIyMjIEFjdXRlIHRyZWF0bWVudHMKClRoaXMgY29kZSBkb2VzIHRoZSBmb2xsb3dpbmc6CgoxLiBFeHRyYWN0cyB0aGUgdW5pcXVlIGxpZmUuc3RhZ2UgbGV2ZWxzIGZyb20gdGhlIGRhdGEgZnJhbWUuCjIuIEZvciBlYWNoIGxpZmUuc3RhZ2UsIGV4dHJhY3RzIHRoZSB1bmlxdWUgYWN1dGUudHJlYXRtZW50IGxldmVscy4KMy4gR2VuZXJhdGVzIGFsbCBwb3NzaWJsZSBwYWlycyBvZiBhY3V0ZS50cmVhdG1lbnQgbGV2ZWxzIHdpdGhpbiBlYWNoIGxpZmUuc3RhZ2UuCjQuIEl0ZXJhdGVzIG92ZXIgZWFjaCBwYWlyIGFuZCBwZXJmb3JtcyB0aGUgdC10ZXN0IGZvciBlYWNoIFRhcmdldC4gQWRkcyBhbgphc3RlcmlzayBjb2x1bW4gYW5kIGFuIGFzdGVyaXNrIGlmIHRoZSBwLXZhbHVlIGlzIDw9IDAuMDUuIFVzZWZ1bCBmb3IgZG93bnN0cmVhbQpwYXJzaW5nLgo1LiBTdG9yZXMgdGhlIHJlc3VsdHMgaW4gYSBsaXN0IGFuZCBjb21iaW5lcyB0aGVtIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZS4KNi4gQWRkcyBhIGNvbXBhcmlzb24gY29sdW1uIHRvIGluZGljYXRlIHdoaWNoIGxpZmUuc3RhZ2UgYW5kIGFjdXRlLnRyZWF0bWVudCBsZXZlbHMgd2VyZSBjb21wYXJlZC4KCkV4Y2x1ZGVzIGBzZWVkYCBhbmQgYHNwYXRgLCBhcyB0aGVzZSB3ZXJlIG9ubHkgaGVsZCBhdCBgYW1iaWVudGAgZm9yIHRoZSBhY3V0ZSB0cmVhdG1lbnQuCmBgYHtyIGFjdXRlLXRyZWF0bWVudHMtbGlmZS1zdGFnZXMsIGV2YWw9VFJVRX0KIyBFeHRyYWN0IHVuaXF1ZSBsaWZlLnN0YWdlIGxldmVscywgZXhjbHVkaW5nICdzZWVkJyBhbmQgJ3NwYXQnCnVuaXF1ZV9saWZlX3N0YWdlcyA8LSB1bmlxdWUoZGVsdGFfQ3FfZGYkbGlmZS5zdGFnZSkKdW5pcXVlX2xpZmVfc3RhZ2VzIDwtIHNldGRpZmYodW5pcXVlX2xpZmVfc3RhZ2VzLCBjKCJzZWVkIiwgInNwYXQiKSkKCiMgSW5pdGlhbGl6ZSBhIGxpc3QgdG8gc3RvcmUgcmVzdWx0cwphY3V0ZV90cmVhdG1lbnRfdF90ZXN0X3Jlc3VsdHNfbGlzdCA8LSBsaXN0KCkKCmZvciAoc3RhZ2UgaW4gdW5pcXVlX2xpZmVfc3RhZ2VzKSB7CiAgIyBFeHRyYWN0IHVuaXF1ZSBhY3V0ZS50cmVhdG1lbnQgbGV2ZWxzIHdpdGhpbiB0aGUgY3VycmVudCBsaWZlLnN0YWdlCiAgdW5pcXVlX3RyZWF0bWVudHMgPC0gdW5pcXVlKGRlbHRhX0NxX2RmICU+JSBmaWx0ZXIobGlmZS5zdGFnZSA9PSBzdGFnZSkgJT4lIHB1bGwoYWN1dGUudHJlYXRtZW50KSkKICAKICAjIENoZWNrIGlmIHRoZXJlIGFyZSBhdCBsZWFzdCAyIHVuaXF1ZSB0cmVhdG1lbnRzCiAgaWYgKGxlbmd0aCh1bmlxdWVfdHJlYXRtZW50cykgPj0gMikgewogICAgIyBHZW5lcmF0ZSBhbGwgcG9zc2libGUgcGFpcnMgb2YgYWN1dGUudHJlYXRtZW50IGxldmVscwogICAgdHJlYXRtZW50X3BhaXJzIDwtIGNvbWJuKHVuaXF1ZV90cmVhdG1lbnRzLCAyLCBzaW1wbGlmeSA9IEZBTFNFKQogICAgCiAgICBmb3IgKHBhaXIgaW4gdHJlYXRtZW50X3BhaXJzKSB7CiAgICAgIHRyZWF0bWVudDEgPC0gcGFpclsxXQogICAgICB0cmVhdG1lbnQyIDwtIHBhaXJbMl0KICAgICAgCiAgICAgICMgUGVyZm9ybSB0LXRlc3QgZm9yIGVhY2ggVGFyZ2V0IGNvbXBhcmluZyB0aGUgdHdvIGFjdXRlLnRyZWF0bWVudCBsZXZlbHMgd2l0aGluIHRoZSBjdXJyZW50IGxpZmUuc3RhZ2UKICAgICAgdF90ZXN0X3Jlc3VsdHMgPC0gZGVsdGFfQ3FfZGYgJT4lCiAgICAgICAgZmlsdGVyKGxpZmUuc3RhZ2UgPT0gc3RhZ2UsIGFjdXRlLnRyZWF0bWVudCAlaW4lIGModHJlYXRtZW50MSwgdHJlYXRtZW50MikpICU+JQogICAgICAgIGdyb3VwX2J5KFRhcmdldCkgJT4lCiAgICAgICAgc3VtbWFyaXNlKAogICAgICAgICAgdF90ZXN0X3Jlc3VsdCA9IGxpc3QodC50ZXN0KGRlbHRhX0NxIH4gYWN1dGUudHJlYXRtZW50KSkKICAgICAgICApICU+JQogICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICBtdXRhdGUoCiAgICAgICAgICBlc3RpbWF0ZV9kaWZmID0gc2FwcGx5KHRfdGVzdF9yZXN1bHQsIGZ1bmN0aW9uKHgpIHgkZXN0aW1hdGVbMV0gLSB4JGVzdGltYXRlWzJdKSwKICAgICAgICAgIHBfdmFsdWUgPSBzYXBwbHkodF90ZXN0X3Jlc3VsdCwgZnVuY3Rpb24oeCkgeCRwLnZhbHVlKSwKICAgICAgICAgIGFzdGVyaXNrID0gaWZlbHNlKHBfdmFsdWUgPD0gMC4wNSwgIioiLCAiIiksICMgQWRkcyBhc3RlcmlzayBjb2x1bW4gYW5kIGFzdGVyaXNrIGZvciBwLXZhbHVlLgogICAgICAgICAgY29tcGFyaXNvbiA9IHBhc3RlKHN0YWdlLCB0cmVhdG1lbnQxLCAidnMiLCB0cmVhdG1lbnQyLCBzZXAgPSAiLiIpCiAgICAgICAgKSAlPiUKICAgICAgICBzZWxlY3QoIXRfdGVzdF9yZXN1bHQpCiAgICAgIAogICAgICBhY3V0ZV90cmVhdG1lbnRfdF90ZXN0X3Jlc3VsdHNfbGlzdFtbcGFzdGUoc3RhZ2UsIHRyZWF0bWVudDEsIHRyZWF0bWVudDIsIHNlcCA9ICIuIildXSA8LSB0X3Rlc3RfcmVzdWx0cwogICAgfQogIH0KfQoKIyBDb21iaW5lIHJlc3VsdHMgaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lCmFjdXRlX3RyZWF0bWVudF90X3Rlc3RfcmVzdWx0c19kZiA8LSBiaW5kX3Jvd3MoYWN1dGVfdHJlYXRtZW50X3RfdGVzdF9yZXN1bHRzX2xpc3QsIC5pZCA9ICJjb21wYXJpc29uIikKCiMgVmlldyB0aGUgcmVzdWx0cwpwcmludChhY3V0ZV90cmVhdG1lbnRfdF90ZXN0X3Jlc3VsdHNfZGYpCgpgYGAKCiMjIyBBY3V0ZSB3aXRoaW4gbGlmZSBzdGFnZSBhbmQgY29uZGl0aW9uaW5nCmBgYHtyIGFjdXRlLXRyZWF0bWVudHMtd2l0aGluLWxpZmUtc3RhZ2VzLWNvbmRpdGlvbmluZywgZXZhbD1UUlVFfQojIEV4dHJhY3QgdW5pcXVlIGxpZmUuc3RhZ2UgbGV2ZWxzLCBleGNsdWRpbmcgJ3NlZWQnIGFuZCAnc3BhdCcKdW5pcXVlX2xpZmVfc3RhZ2VzIDwtIHVuaXF1ZShkZWx0YV9DcV9kZiRsaWZlLnN0YWdlKQojdW5pcXVlX2xpZmVfc3RhZ2VzIDwtIHNldGRpZmYodW5pcXVlX2xpZmVfc3RhZ2VzLCBjKCJzZWVkIiwgInNwYXQiKSkKCiMgRXh0cmFjdCB1bmlxdWUgY29uZGl0aW9uaW5nLnRyZWF0bWVudCBsZXZlbHMKdW5pcXVlX2NvbmRpdGlvbmluZ190cmVhdG1lbnRzIDwtIHVuaXF1ZShkZWx0YV9DcV9kZiRjb25kaXRpb25pbmcudHJlYXRtZW50KQoKIyBJbml0aWFsaXplIGEgbGlzdCB0byBzdG9yZSByZXN1bHRzCmFjdXRlX3RyZWF0bWVudF93aXRoaW5fbGlmZS5zdGFnZXNfY29uZGl0aW9uaW5nX3RfdGVzdF9yZXN1bHRzX2xpc3QgPC0gbGlzdCgpCgpmb3IgKHN0YWdlIGluIHVuaXF1ZV9saWZlX3N0YWdlcykgewogIGZvciAoY29uZGl0aW9uaW5nIGluIHVuaXF1ZV9jb25kaXRpb25pbmdfdHJlYXRtZW50cykgewogICAgIyBFeHRyYWN0IHVuaXF1ZSBhY3V0ZS50cmVhdG1lbnQgbGV2ZWxzIHdpdGhpbiB0aGUgY3VycmVudCBsaWZlLnN0YWdlIGFuZCBjb25kaXRpb25pbmcudHJlYXRtZW50CiAgICB1bmlxdWVfdHJlYXRtZW50cyA8LSB1bmlxdWUoZGVsdGFfQ3FfZGYgJT4lIGZpbHRlcihsaWZlLnN0YWdlID09IHN0YWdlLCBjb25kaXRpb25pbmcudHJlYXRtZW50ID09IGNvbmRpdGlvbmluZykgJT4lIHB1bGwoYWN1dGUudHJlYXRtZW50KSkKICAgIAogICAgIyBDaGVjayBpZiB0aGVyZSBhcmUgYXQgbGVhc3QgMiB1bmlxdWUgdHJlYXRtZW50cwogICAgaWYgKGxlbmd0aCh1bmlxdWVfdHJlYXRtZW50cykgPj0gMikgewogICAgICAjIEdlbmVyYXRlIGFsbCBwb3NzaWJsZSBwYWlycyBvZiBhY3V0ZS50cmVhdG1lbnQgbGV2ZWxzCiAgICAgIHRyZWF0bWVudF9wYWlycyA8LSBjb21ibih1bmlxdWVfdHJlYXRtZW50cywgMiwgc2ltcGxpZnkgPSBGQUxTRSkKICAgICAgCiAgICAgIGZvciAocGFpciBpbiB0cmVhdG1lbnRfcGFpcnMpIHsKICAgICAgICB0cmVhdG1lbnQxIDwtIHBhaXJbMV0KICAgICAgICB0cmVhdG1lbnQyIDwtIHBhaXJbMl0KICAgICAgICAKICAgICAgICAjIFBlcmZvcm0gdC10ZXN0IGZvciBlYWNoIFRhcmdldCBjb21wYXJpbmcgdGhlIHR3byBhY3V0ZS50cmVhdG1lbnQgbGV2ZWxzIHdpdGhpbiB0aGUgY3VycmVudCBsaWZlLnN0YWdlIGFuZCBjb25kaXRpb25pbmcudHJlYXRtZW50CiAgICAgICAgdF90ZXN0X3Jlc3VsdHMgPC0gZGVsdGFfQ3FfZGYgJT4lCiAgICAgICAgICBmaWx0ZXIobGlmZS5zdGFnZSA9PSBzdGFnZSwgY29uZGl0aW9uaW5nLnRyZWF0bWVudCA9PSBjb25kaXRpb25pbmcsIGFjdXRlLnRyZWF0bWVudCAlaW4lIGModHJlYXRtZW50MSwgdHJlYXRtZW50MikpICU+JQogICAgICAgICAgZ3JvdXBfYnkoVGFyZ2V0KSAlPiUKICAgICAgICAgIHN1bW1hcmlzZSgKICAgICAgICAgICAgdF90ZXN0X3Jlc3VsdCA9IGxpc3QodC50ZXN0KGRlbHRhX0NxIH4gYWN1dGUudHJlYXRtZW50KSkKICAgICAgICAgICkgJT4lCiAgICAgICAgICB1bmdyb3VwKCkgJT4lCiAgICAgICAgICBtdXRhdGUoCiAgICAgICAgICAgIGVzdGltYXRlX2RpZmYgPSBzYXBwbHkodF90ZXN0X3Jlc3VsdCwgZnVuY3Rpb24oeCkgeCRlc3RpbWF0ZVsxXSAtIHgkZXN0aW1hdGVbMl0pLAogICAgICAgICAgICBwX3ZhbHVlID0gc2FwcGx5KHRfdGVzdF9yZXN1bHQsIGZ1bmN0aW9uKHgpIHgkcC52YWx1ZSksCiAgICAgICAgICAgIGFzdGVyaXNrID0gaWZlbHNlKHBfdmFsdWUgPD0gMC4wNSwgIioiLCAiIiksICMgQWRkcyBhc3RlcmlzayBjb2x1bW4gYW5kIGFzdGVyaXNrIGZvciBwLXZhbHVlLgogICAgICAgICAgICBjb21wYXJpc29uID0gcGFzdGUoc3RhZ2UsIGNvbmRpdGlvbmluZywgdHJlYXRtZW50MSwgInZzIiwgdHJlYXRtZW50Miwgc2VwID0gIi4iKQogICAgICAgICAgKSAlPiUKICAgICAgICAgIHNlbGVjdCghdF90ZXN0X3Jlc3VsdCkKICAgICAgICAKICAgICAgICBhY3V0ZV90cmVhdG1lbnRfd2l0aGluX2xpZmUuc3RhZ2VzX2NvbmRpdGlvbmluZ190X3Rlc3RfcmVzdWx0c19saXN0W1twYXN0ZShzdGFnZSwgY29uZGl0aW9uaW5nLCB0cmVhdG1lbnQxLCB0cmVhdG1lbnQyLCBzZXAgPSAiLiIpXV0gPC0gdF90ZXN0X3Jlc3VsdHMKICAgICAgfQogICAgfQogIH0KfQoKIyBDb21iaW5lIHJlc3VsdHMgaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lCmFjdXRlX3RyZWF0bWVudF93aXRoaW5fbGlmZS5zdGFnZXNfY29uZGl0aW9uaW5nX3RfdGVzdF9yZXN1bHRzX2RmIDwtIGJpbmRfcm93cyhhY3V0ZV90cmVhdG1lbnRfd2l0aGluX2xpZmUuc3RhZ2VzX2NvbmRpdGlvbmluZ190X3Rlc3RfcmVzdWx0c19saXN0LCAuaWQgPSAiY29tcGFyaXNvbl9pZCIpCgojIFZpZXcgdGhlIHJlc3VsdHMKcHJpbnQoYWN1dGVfdHJlYXRtZW50X3dpdGhpbl9saWZlLnN0YWdlc19jb25kaXRpb25pbmdfdF90ZXN0X3Jlc3VsdHNfZGYpCmBgYAoKIyMgUGxvdHRpbmcKCiMjIyBEZWx0YSBDcSBib3hwbG90cwoKIyMjIyBMaWZlc3RhZ2UgY29tcGFyaXNvbnMKYGBge3IgZGVsdGEtQ3EtYm94cGxvdHMtbGlmZXN0YWdlLCBldmFsPVRSVUV9CiMgQ3JlYXRlIGJveCBwbG90cyBmb3IgZWFjaCBjb21wYXJpc29uCnVuaXF1ZV9jb21wYXJpc29ucyA8LSB1bmlxdWUobGlmZV9zdGFnZV90X3Rlc3RfcmVzdWx0c19kZiRjb21wYXJpc29uKQoKZm9yIChjb21wYXJpc29uIGluIHVuaXF1ZV9jb21wYXJpc29ucykgewogIGNyZWF0ZV9ib3hwbG90X2RlbHRhX0NxKGRlbHRhX0NxX2RmLCBjb21wYXJpc29uLCBsaWZlX3N0YWdlX3RfdGVzdF9yZXN1bHRzX2RmKQp9CmBgYAoKIyMjIENvbmRpdGlvbmluZyBjb21wYXJpc29ucwpgYGB7ciBkZWx0YS1DcS1ib3hwbG90cy1jb25kaXRpb25pbmcsIGV2YWw9VFJVRX0KCiMgQ3JlYXRlIGJveCBwbG90cyBmb3IgZWFjaCBjb21wYXJpc29uCnVuaXF1ZV9jb21wYXJpc29ucyA8LSB1bmlxdWUoY29uZGl0aW9uaW5nX3RyZWF0bWVudF90X3Rlc3RfcmVzdWx0c19kZiRjb21wYXJpc29uKQoKZm9yIChjb21wYXJpc29uIGluIHVuaXF1ZV9jb21wYXJpc29ucykgewogIGNyZWF0ZV9ib3hwbG90X2NvbmRpdGlvbmluZyhkZWx0YV9DcV9kZiwgY29tcGFyaXNvbiwgY29uZGl0aW9uaW5nX3RyZWF0bWVudF90X3Rlc3RfcmVzdWx0c19kZikKfQpgYGAKCiMjIyBBY3V0ZSB0cmVhdG1lbnQgY29tcGFyaXNvbnMKYGBge3IgZGVsdGEtQ3EtYm94cGxvdHMtYWN1dGUtdHJlYXRtZW50LCBldmFsPVRSVUV9CiMgQ3JlYXRlIGJveCBwbG90cyBmb3IgZWFjaCBjb21wYXJpc29uCnVuaXF1ZV9jb21wYXJpc29ucyA8LSB1bmlxdWUoYWN1dGVfdHJlYXRtZW50X3RfdGVzdF9yZXN1bHRzX2RmJGNvbXBhcmlzb24pCgpmb3IgKGNvbXBhcmlzb24gaW4gdW5pcXVlX2NvbXBhcmlzb25zKSB7CiAgY3JlYXRlX2JveHBsb3RfYWN1dGUoZGVsdGFfQ3FfZGYsIGNvbXBhcmlzb24sIGFjdXRlX3RyZWF0bWVudF90X3Rlc3RfcmVzdWx0c19kZikKfQpgYGAKCiMjIyBBY3V0ZSB3aXRoaW4gbGlmZSBzdGFnZSBjb25kaXRpb25pbmcKYGBge3IgYm94cGxvdHMtYWN1dGUtdHJlYXRtZW50cy13aXRoaW4tbGlmZS1zdGFnZXMtY29uZGl0aW9uaW5nLCBldmFsPVRSVUV9CiMgTG9vcCB0aHJvdWdoIGVhY2ggY29tcGFyaXNvbiBpbiB0aGUgdC10ZXN0IHJlc3VsdHMgYW5kIGNyZWF0ZSBib3ggcGxvdHMKZm9yIChjb21wYXJpc29uIGluIHVuaXF1ZShhY3V0ZV90cmVhdG1lbnRfd2l0aGluX2xpZmUuc3RhZ2VzX2NvbmRpdGlvbmluZ190X3Rlc3RfcmVzdWx0c19kZiRjb21wYXJpc29uKSkgewogIGNyZWF0ZV9ib3hwbG90X2FjdXRlX2NvbmRpdGlvbmluZyhkZWx0YV9DcV9kZiwgY29tcGFyaXNvbiwgYWN1dGVfdHJlYXRtZW50X3dpdGhpbl9saWZlLnN0YWdlc19jb25kaXRpb25pbmdfdF90ZXN0X3Jlc3VsdHNfZGYpCn0KYGBgCgoKIyBEZWx0YSBkZWx0YSBDcQoKIyMgQ2FsY3VsYXRpb25zCgojIyMgQ29uZGl0aW9uaW5nCmBgYHtyIGRlbHRhLWRlbHRhLUNxLWNvbmRpdGlvbmluZywgZXZhbD1UUlVFfQojIENhbGN1bGF0ZSBkZWx0YV9kZWx0YV9DcQpkZWx0YV9kZWx0YV9jb25kaXRpb25pbmdfZm9sZF9jaGFuZ2UgPC0gZGVsdGFfQ3FfZGYgJT4lCiAgZ3JvdXBfYnkobGlmZS5zdGFnZSwgVGFyZ2V0KSAlPiUKICBzdW1tYXJpemUoCiAgICB0cmVhdGVkX2RlbHRhX0NxID0gbWVhbihkZWx0YV9DcVtjb25kaXRpb25pbmcudHJlYXRtZW50ID09ICJ0cmVhdGVkIl0sIG5hLnJtID0gVFJVRSksCiAgICBjb250cm9sX2RlbHRhX0NxID0gbWVhbihkZWx0YV9DcVtjb25kaXRpb25pbmcudHJlYXRtZW50ID09ICJjb250cm9sIl0sIG5hLnJtID0gVFJVRSkKICApICU+JQogIG11dGF0ZShkZWx0YV9kZWx0YV9DcSA9IHRyZWF0ZWRfZGVsdGFfQ3EgLSBjb250cm9sX2RlbHRhX0NxKSAlPiUKICBzZWxlY3QobGlmZS5zdGFnZSwgVGFyZ2V0LCBkZWx0YV9kZWx0YV9DcSkKCnN0cihkZWx0YV9kZWx0YV9jb25kaXRpb25pbmdfZm9sZF9jaGFuZ2UpCmBgYAoKIyMjIEFjdXRlIHRyZWF0bWVudApgYGB7ciBkZWx0YS1kZWx0YS1DcS1hY3V0ZSwgZXZhbD1UUlVFfQojIENhbGN1bGF0ZSBkZWx0YV9kZWx0YV9DcSBmb3IgYWN1dGUgdHJlYXRtZW50CmRlbHRhX2RlbHRhX0NxX2FjdXRlX2RmIDwtIGRlbHRhX0NxX2RmICU+JQogIGdyb3VwX2J5KGxpZmUuc3RhZ2UsIFRhcmdldCwgYWN1dGUudHJlYXRtZW50KSAlPiUKICBzdW1tYXJpemUoCiAgICB0cmVhdGVkX2RlbHRhX0NxID0gbWVhbihkZWx0YV9DcVtjb25kaXRpb25pbmcudHJlYXRtZW50ID09ICJ0cmVhdGVkIl0sIG5hLnJtID0gVFJVRSksCiAgICBjb250cm9sX2RlbHRhX0NxID0gbWVhbihkZWx0YV9DcVtjb25kaXRpb25pbmcudHJlYXRtZW50ID09ICJjb250cm9sIl0sIG5hLnJtID0gVFJVRSkKICApICU+JQogIG11dGF0ZShkZWx0YV9kZWx0YV9DcSA9IHRyZWF0ZWRfZGVsdGFfQ3EgLSBjb250cm9sX2RlbHRhX0NxKSAlPiUKICBzZWxlY3QobGlmZS5zdGFnZSwgVGFyZ2V0LCBhY3V0ZS50cmVhdG1lbnQsIGRlbHRhX2RlbHRhX0NxKQoKc3RyKGRlbHRhX2RlbHRhX0NxX2FjdXRlX2RmKQoKYGBgCgojIyMgTGlmZSBzdGFnZQpgYGB7ciBkZWx0YS1kZWx0YS1DcS1saWZlLXN0YWdlLCBldmFsPVRSVUV9CiMgQ2FsY3VsYXRlIGRlbHRhX2RlbHRhX0NxIGZvciBsaWZlIHN0YWdlIGNvbXBhcmlzb25zCmRlbHRhX2RlbHRhX0NxX2xpZmVfc3RhZ2VfZGYgPC0gZGVsdGFfQ3FfZGYgJT4lCiAgZ3JvdXBfYnkoVGFyZ2V0LCBsaWZlLnN0YWdlKSAlPiUKICBzdW1tYXJpemUobWVhbl9kZWx0YV9DcSA9IG1lYW4oZGVsdGFfQ3EsIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbGlmZS5zdGFnZSwgdmFsdWVzX2Zyb20gPSBtZWFuX2RlbHRhX0NxKSAlPiUKICBtdXRhdGUoCiAgICBkZWx0YV9kZWx0YV9DcV9hZHVsdF92c19zZWVkID0gYWR1bHQgLSBzZWVkLAogICAgZGVsdGFfZGVsdGFfQ3Ffc3BhdF92c19zZWVkID0gc3BhdCAtIHNlZWQsCiAgICBkZWx0YV9kZWx0YV9DcV9hZHVsdF92c19zcGF0ID0gYWR1bHQgLSBzcGF0CiAgKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IHN0YXJ0c193aXRoKCJkZWx0YV9kZWx0YV9DcV8iKSwgbmFtZXNfdG8gPSAiY29tcGFyaXNvbiIsIHZhbHVlc190byA9ICJkZWx0YV9kZWx0YV9DcSIpICU+JQogIGZpbHRlcighaXMubmEoZGVsdGFfZGVsdGFfQ3EpKQoKIyBEaXNwbGF5IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHJlc3VsdGluZyBkYXRhIGZyYW1lCnN0cihkZWx0YV9kZWx0YV9DcV9saWZlX3N0YWdlX2RmKQpgYGAKCiMjIyBDYWxjdWxhdGUgZGVsdGEgZGVsdGEgYWN1dGUgdHJlYXRtZW50cyB3aXRoaW4gbGlmZXN0YWdlIGFuZCBjb25kaXRpb25pbmcKYGBge3IgZGVsdGEtZGVsdGEtQ3EtYWN1dGUtd2l0aGluLWxpZmUtc3RhZ2UtY29uZGl0aW9uaW5nLCBldmFsPVRSVUV9CiMgQ2FsY3VsYXRlIGRlbHRhX2RlbHRhX0NxIGZvciBhY3V0ZSB0cmVhdG1lbnQgY29tcGFyaXNvbnMgd2l0aGluIGVhY2ggbGlmZSBzdGFnZSBhbmQgY29uZGl0aW9uaW5nIHRyZWF0bWVudApkZWx0YV9kZWx0YV9DcV9hY3V0ZV93aXRoaW5fbGlmZV9zdGFnZV9jb25kaXRpb25pbmdfZGYgPC0gZGVsdGFfQ3FfZGYgJT4lCiAgZ3JvdXBfYnkobGlmZS5zdGFnZSwgY29uZGl0aW9uaW5nLnRyZWF0bWVudCwgVGFyZ2V0LCBhY3V0ZS50cmVhdG1lbnQpICU+JQogIHN1bW1hcml6ZShtZWFuX2RlbHRhX0NxID0gbWVhbihkZWx0YV9DcSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBhY3V0ZS50cmVhdG1lbnQsIHZhbHVlc19mcm9tID0gbWVhbl9kZWx0YV9DcSkgJT4lCiAgbXV0YXRlKGRlbHRhX2RlbHRhX0NxX2hpZ2hfdnNfYW1iaWVudCA9IGhpZ2ggLSBhbWJpZW50KSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IHN0YXJ0c193aXRoKCJkZWx0YV9kZWx0YV9DcV8iKSwgbmFtZXNfdG8gPSAiY29tcGFyaXNvbiIsIHZhbHVlc190byA9ICJkZWx0YV9kZWx0YV9DcSIpICU+JQogIGZpbHRlcighaXMubmEoZGVsdGFfZGVsdGFfQ3EpKQoKIyBEaXNwbGF5IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHJlc3VsdGluZyBkYXRhIGZyYW1lCnN0cihkZWx0YV9kZWx0YV9DcV9hY3V0ZV93aXRoaW5fbGlmZV9zdGFnZV9jb25kaXRpb25pbmdfZGYpCmBgYAoKIyMjIENhbGN1bGF0ZSB0aGUgZm9sZCBjaGFuZ2UgbGlmZSBzdGFnZSBjb21wYXJpc29uCmBgYHtyIGZvbGQtY2hhbmdlLWxpZmUtc3RhZ2UsIGV2YWw9VFJVRX0KIyBDYWxjdWxhdGUgZm9sZCBjaGFuZ2UgYW5kIG91dHB1dCB0byBhIG5ldyBkYXRhIGZyYW1lCmZvbGRfY2hhbmdlX2xpZmVfc3RhZ2VfZGYgPC0gZGVsdGFfZGVsdGFfQ3FfbGlmZV9zdGFnZV9kZiAlPiUKICBtdXRhdGUoZm9sZF9jaGFuZ2UgPSAyXigtZGVsdGFfZGVsdGFfQ3EpKQoKIyBEaXNwbGF5IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHJlc3VsdGluZyBkYXRhIGZyYW1lCnN0cihmb2xkX2NoYW5nZV9saWZlX3N0YWdlX2RmKQpgYGAKCiMjIyBDYWxjdWxhdGUgdGhlIGZvbGQgY2hhbmdlIGNvbmRpdGlvbmluZyBjb21wYXJpc29uCmBgYHtyIGZvbGQtY2hhbmdlLWNvbmRpdGlvbiwgZXZhbD1UUlVFfQpkZWx0YV9kZWx0YV9jb25kaXRpb25pbmdfZm9sZF9jaGFuZ2UgPC0gZGVsdGFfZGVsdGFfY29uZGl0aW9uaW5nX2ZvbGRfY2hhbmdlICU+JQogIG11dGF0ZShmb2xkX2NoYW5nZSA9IDJeKC1kZWx0YV9kZWx0YV9DcSkpICU+JSAKICBkaXN0aW5jdChUYXJnZXQsIGZvbGRfY2hhbmdlKQoKc3RyKGRlbHRhX2RlbHRhX2NvbmRpdGlvbmluZ19mb2xkX2NoYW5nZSkKYGBgCgoKIyMjIENhbGN1bGF0ZSB0aGUgZm9sZCBjaGFuZ2UgYWN1dGUgY29tcGFyaXNvbgpgYGB7ciBmb2xkLWNoYW5nZS1hY3V0ZSwgZXZhbD1UUlVFfQojIENhbGN1bGF0ZSBmb2xkIGNoYW5nZSBmb3IgYWN1dGUgdHJlYXRtZW50CmRlbHRhX2RlbHRhX2FjdXRlX2ZvbGRfY2hhbmdlIDwtIGRlbHRhX2RlbHRhX0NxX2FjdXRlX2RmICU+JQogIG11dGF0ZShmb2xkX2NoYW5nZSA9IDJeKC1kZWx0YV9kZWx0YV9DcSkpICU+JQogIGRpc3RpbmN0KGxpZmUuc3RhZ2UsIFRhcmdldCwgYWN1dGUudHJlYXRtZW50LCBmb2xkX2NoYW5nZSkKCiMgRGlzcGxheSB0aGUgc3RydWN0dXJlIG9mIHRoZSByZXN1bHRpbmcgZGF0YSBmcmFtZQpzdHIoZGVsdGFfZGVsdGFfYWN1dGVfZm9sZF9jaGFuZ2UpCmBgYAoKIyMjIENhbGN1bGF0ZSBmb2xkIGNoYW5nZSBhY3V0ZSB0cmVhdG1lbnRzIHdpdGhpbiBsaWZlc3RhZ2UgYW5kIGNvbmRpdGlvbmluZwpgYGB7ciBmb2xkLWNoYW5nZS1hY3V0ZS13aXRoaW4tbGlmZS1zdGFnZS1jb25kaXRpb25pbmcsIGV2YWw9VFJVRX0KIyBDYWxjdWxhdGUgZm9sZCBjaGFuZ2UgZm9yIGFjdXRlIHRyZWF0bWVudCBjb21wYXJpc29ucyB3aXRoaW4gZWFjaCBsaWZlIHN0YWdlIGFuZCBjb25kaXRpb25pbmcgdHJlYXRtZW50CmZvbGRfY2hhbmdlX2FjdXRlX3dpdGhpbl9saWZlX3N0YWdlX2NvbmRpdGlvbmluZ19kZiA8LSBkZWx0YV9kZWx0YV9DcV9hY3V0ZV93aXRoaW5fbGlmZV9zdGFnZV9jb25kaXRpb25pbmdfZGYgJT4lCiAgbXV0YXRlKGZvbGRfY2hhbmdlID0gMl4oLWRlbHRhX2RlbHRhX0NxKSkKCiMgRGlzcGxheSB0aGUgc3RydWN0dXJlIG9mIHRoZSByZXN1bHRpbmcgZGF0YSBmcmFtZQpzdHIoZm9sZF9jaGFuZ2VfYWN1dGVfd2l0aGluX2xpZmVfc3RhZ2VfY29uZGl0aW9uaW5nX2RmKQpgYGAKCiMjIFBsb3R0aW5nIGZvbGQgY2hhbmdlcwoKIyMjIEFjdXRlIGNvbXBhcmlzb25zIHdpdGhpbiBsaWZlc3RhZ2UgYW5kIGNvbmRpdGlvbmluZwpgYGB7ciBiYXItcGxvdHMtZm9sZC1jaGFuZ2UtYWN1dGUtd2l0aGluLWxpZmVzdGFnZS1jb25kaXRpb25pbmcsIGV2YWw9VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQoKIyBHZW5lcmF0ZSBiYXIgcGxvdHMgZm9yIGVhY2ggZ3JvdXAgb2YgY29tcGFyaXNvbiB3aXRoaW4gZWFjaCBsaWZlIHN0YWdlIGFuZCBjb25kaXRpb25pbmcgdHJlYXRtZW50CnBsb3RfbGlzdCA8LSBmb2xkX2NoYW5nZV9hY3V0ZV93aXRoaW5fbGlmZV9zdGFnZV9jb25kaXRpb25pbmdfZGYgJT4lCiAgc3BsaXQobGlzdCguJGxpZmUuc3RhZ2UsIC4kY29uZGl0aW9uaW5nLnRyZWF0bWVudCwgLiRjb21wYXJpc29uKSkgJT4lCiAgbGFwcGx5KGZ1bmN0aW9uKGRmKSB7CiAgICBsaWZlX3N0YWdlIDwtIHVuaXF1ZShkZiRsaWZlLnN0YWdlKQogICAgY29uZGl0aW9uaW5nX3RyZWF0bWVudCA8LSB1bmlxdWUoZGYkY29uZGl0aW9uaW5nLnRyZWF0bWVudCkKICAgIGNvbXBhcmlzb25fdGl0bGUgPC0gZ3N1YigiZGVsdGFfZGVsdGFfQ3FfIiwgIiIsIHVuaXF1ZShkZiRjb21wYXJpc29uKSkKICAgIGNvbXBhcmlzb25fdGl0bGUgPC0gZ3N1YigiX3ZzXyIsICIgdnMuICIsIGNvbXBhcmlzb25fdGl0bGUpCiAgICBnZ3Bsb3QoZGYsIGFlcyh4ID0gVGFyZ2V0LCB5ID0gZm9sZF9jaGFuZ2UpKSArCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiR2VuZSBFeHByZXNzaW9uIC0iLCBsaWZlX3N0YWdlLCAiLSIsIGNvbmRpdGlvbmluZ190cmVhdG1lbnQsICItIiwgY29tcGFyaXNvbl90aXRsZSksIAogICAgICAgICAgIHggPSAiVGFyZ2V0IiwgeSA9ICJGb2xkIENoYW5nZSIpICsKICAgICAgdGhlbWVfbWluaW1hbCgpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKICB9KQoKIyBEaXNwbGF5IHRoZSBwbG90cwpmb3IgKHBsb3QgaW4gcGxvdF9saXN0KSB7CiAgcHJpbnQocGxvdCkKfQpgYGAKCiMjIyBMaWZlIHN0YWdlIGNvbXBhcmlzb25zCmBgYHtyIGJhci1wbG90cy1mb2xkLWNoYW5nZS1saWZlc3RhZ2VzLCBldmFsPVRSVUV9CgojIEdlbmVyYXRlIGJhciBwbG90cyBmb3IgZWFjaCBncm91cCBvZiBjb21wYXJpc29uCnBsb3RfbGlzdCA8LSBmb2xkX2NoYW5nZV9saWZlX3N0YWdlX2RmICU+JQogIHNwbGl0KC4kY29tcGFyaXNvbikgJT4lCiAgbGFwcGx5KGZ1bmN0aW9uKGRmKSB7CiAgICBjb21wYXJpc29uX3RpdGxlIDwtIGdzdWIoImRlbHRhX2RlbHRhX0NxXyIsICIiLCB1bmlxdWUoZGYkY29tcGFyaXNvbikpCiAgICBjb21wYXJpc29uX3RpdGxlIDwtIGdzdWIoIl92c18iLCAiIHZzLiAiLCBjb21wYXJpc29uX3RpdGxlKQogICAgZ2dwbG90KGRmLCBhZXMoeCA9IFRhcmdldCwgeSA9IGZvbGRfY2hhbmdlKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBsYWJzKHRpdGxlID0gcGFzdGUoIkdlbmUgRXhwcmVzc2lvbiAtIiwgY29tcGFyaXNvbl90aXRsZSksIHggPSAiVGFyZ2V0IiwgeSA9ICJGb2xkIENoYW5nZSIpICsKICAgICAgdGhlbWVfbWluaW1hbCgpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKICB9KQoKIyBEaXNwbGF5IHRoZSBwbG90cwpmb3IgKHBsb3QgaW4gcGxvdF9saXN0KSB7CiAgcHJpbnQocGxvdCkKfQpgYGAKCiMjIyBDb25kaXRpb25pbmcgY29tcGFyaXNvbnMKYGBge3IgYmFycGxvdC1mb2xkLWNoYW5nZS1jb25kaXRpb25pbmcsIGVjaG89RkFMU0UsIGV2YWw9VFJVRX0KCiMgQ3JlYXRlIHRoZSBiYXIgcGxvdApnZ3Bsb3QoZGVsdGFfZGVsdGFfY29uZGl0aW9uaW5nX2ZvbGRfY2hhbmdlLCBhZXMoeCA9IFRhcmdldCwgeSA9IGZvbGRfY2hhbmdlLCBmaWxsID0gVGFyZ2V0KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZmFjZXRfd3JhcCh+IGxpZmUuc3RhZ2UsIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkZvbGQgQ2hhbmdlIGluIENvbmRpdGlvbmluZyBFeHByZXNzaW9uIGJ5IFRhcmdldCBhbmQgTGlmZSBTdGFnZSIsCiAgICAgICB4ID0gIlRhcmdldCIsCiAgICAgICB5ID0gIkZvbGQgQ2hhbmdlIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYAoKIyMjIExpbmUgcGxvdCBjb25kaXRpb25pbmcgY29tcGFyaXNvbnMgYWNyb3NzIGxpZmVzdGFnZXMKYGBge3IgbGluZXBsb3QtZm9sZC1jaGFuZ2UtY29uZGl0aW9uaW5nLCBlY2hvPUZBTFNFLCBldmFsPVRSVUV9CiMgRW5zdXJlIGxpZmUuc3RhZ2UgaXMgYSBmYWN0b3Igd2l0aCB0aGUgY29ycmVjdCBvcmRlcgpkZWx0YV9kZWx0YV9jb25kaXRpb25pbmdfZm9sZF9jaGFuZ2UkbGlmZS5zdGFnZSA8LSBmYWN0b3IoZGVsdGFfZGVsdGFfY29uZGl0aW9uaW5nX2ZvbGRfY2hhbmdlJGxpZmUuc3RhZ2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJzZWVkIiwgInNwYXQiLCAianV2ZW5pbGUiLCAiYWR1bHQiKSkKCiMgQ3JlYXRlIHRoZSBsaW5lIHBsb3QKZ2dwbG90KGRlbHRhX2RlbHRhX2NvbmRpdGlvbmluZ19mb2xkX2NoYW5nZSwgYWVzKHggPSBsaWZlLnN0YWdlLCB5ID0gZm9sZF9jaGFuZ2UsIGNvbG9yID0gVGFyZ2V0LCBncm91cCA9IFRhcmdldCkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiRm9sZCBDaGFuZ2UgaW4gQ29uZGl0aW9uaW5nIEV4cHJlc3Npb24gYnkgVGFyZ2V0IGFuZCBMaWZlIFN0YWdlIiwKICAgICAgIHggPSAiTGlmZSBTdGFnZSIsCiAgICAgICB5ID0gIkZvbGQgQ2hhbmdlIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICB5bGltKDAsIE5BKQpgYGAKCiMjIyBBY3V0ZSB0cmVhdG1lbnQgY29tcGFyaXNvbgpgYGB7ciBiYXJwbG90LWZvbGQtY2hhbmdlLWFjdXRlLCBlY2hvPUZBTFNFLCBldmFsPVRSVUV9CiMgQ3JlYXRlIHRoZSBiYXIgcGxvdApnZ3Bsb3QoZGVsdGFfZGVsdGFfYWN1dGVfZm9sZF9jaGFuZ2UsIGFlcyh4ID0gVGFyZ2V0LCB5ID0gZm9sZF9jaGFuZ2UsIGZpbGwgPSBhY3V0ZS50cmVhdG1lbnQpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGZhY2V0X3dyYXAofiBsaWZlLnN0YWdlLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJGb2xkIENoYW5nZSBpbiBBY3V0ZSBUcmVhdG1lbnQgRXhwcmVzc2lvbiBieSBUYXJnZXQgYW5kIExpZmUgU3RhZ2UiLAogICAgICAgeCA9ICJUYXJnZXQiLAogICAgICAgeSA9ICJGb2xkIENoYW5nZSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAKCiMgUnVubmluZyBsaW5lYXIgbW9kZWxzIAoKIyMgQU5PVkEgbW9kZWxzIAoKYGBge3IsIGV2YWw9VFJVRX0KaGlzdChkZWx0YV9DcV9kZiRkZWx0YV9DcSkKYGBgCgpSdW4gYW4gYW5vdmEgbW9kZWwgdG8gdGVzdCBmb3IgZWZmZWN0cyBvZiBsaWZlc3RhZ2UsIGNvbmRpdGlvbmluZywgYW5kIGFjdXRlIHRyZWF0bWVudCBvbiBkZWx0YSBDcSB2YWx1ZXMgZm9yIGVhY2ggdGFyZ2V0LiAKCiMjIyBBVFAgc3ludGhhc2UKCkFUUCBzeW50aGFzZSBpcyBhbiBlbnp5bWUgY29tcGxleCB0aGF0IGZ1bmN0aW9ucyB0byBzeW50aGVzaXplIGFkZW5vc2luZSB0cmlwaG9zcGhhdGUgKEFUUCkgZnJvbSBhZGVub3NpbmUgZGlwaG9zcGhhdGUgKEFEUCkgYW5kIGlub3JnYW5pYyBwaG9zcGhhdGUgKFBpKSwgZXNzZW50aWFsbHkgZ2VuZXJhdGluZyB0aGUgY2VsbCdzIHByaW1hcnkgZW5lcmd5IGN1cnJlbmN5IGJ5IGhhcm5lc3NpbmcgdGhlIGVuZXJneSBmcm9tIGEgcHJvdG9uIGdyYWRpZW50IGFjcm9zcyBhIG1lbWJyYW5lLiAKCmBgYHtyLCBldmFsPVRSVUV9CmxpYnJhcnkoY2FyKQpsaWJyYXJ5KGVtbWVhbnMpCgptb2RlbDwtZGVsdGFfQ3FfZGYlPiUKICBmaWx0ZXIoVGFyZ2V0PT0iQVRQc3ludGhhc2UiKSU+JQogIAogIGFvdihkZWx0YV9DcSB+IGxpZmUuc3RhZ2UgKiBjb25kaXRpb25pbmcudHJlYXRtZW50ICogYWN1dGUudHJlYXRtZW50LCBkYXRhPS4pCgpzdW1tYXJ5KG1vZGVsKQoKcXFQbG90KG1vZGVsJHJlc2lkdWFscykKCmxldmVuZVRlc3QobW9kZWwkcmVzaWR1YWxzIH4gbGlmZS5zdGFnZSpjb25kaXRpb25pbmcudHJlYXRtZW50KmFjdXRlLnRyZWF0bWVudCwgZGF0YT1kZWx0YV9DcV9kZiU+JWZpbHRlcihUYXJnZXQ9PSJBVFBzeW50aGFzZSIpKQpgYGAKTm8gc2lnbmlmaWNhbnQgZWZmZWN0cy4gIAoKIyMjIEROTVQxCgpUaGUgRE5NVDEgZ2VuZSBwcm92aWRlcyBpbnN0cnVjdGlvbnMgZm9yIG1ha2luZyBhbiBlbnp5bWUgY2FsbGVkIEROQSBtZXRoeWx0cmFuc2ZlcmFzZSAxLiBUaGlzIGVuenltZSBpcyBpbnZvbHZlZCBpbiBETkEgbWV0aHlsYXRpb24sIHdoaWNoIGlzIHRoZSBhZGRpdGlvbiBvZiBtZXRoeWwgZ3JvdXBzLCBjb25zaXN0aW5nIG9mIG9uZSBjYXJib24gYXRvbSBhbmQgdGhyZWUgaHlkcm9nZW4gYXRvbXMsIHRvIEROQSBtb2xlY3VsZXMuCgpgYGB7ciwgZXZhbD1UUlVFfQoKbW9kZWw8LWRlbHRhX0NxX2RmJT4lCiAgZmlsdGVyKFRhcmdldD09IkROTVQxIiklPiUKICAKICBhb3YoZGVsdGFfQ3EgfiBsaWZlLnN0YWdlICogY29uZGl0aW9uaW5nLnRyZWF0bWVudCAqIGFjdXRlLnRyZWF0bWVudCwgZGF0YT0uKQoKc3VtbWFyeShtb2RlbCkKCnFxUGxvdChtb2RlbCRyZXNpZHVhbHMpCgpsZXZlbmVUZXN0KG1vZGVsJHJlc2lkdWFscyB+IGxpZmUuc3RhZ2UqY29uZGl0aW9uaW5nLnRyZWF0bWVudCphY3V0ZS50cmVhdG1lbnQsIGRhdGE9ZGVsdGFfQ3FfZGYlPiVmaWx0ZXIoVGFyZ2V0PT0iRE5NVDEiKSkKYGBgCk5vIHNpZ25pZmljYW50IGVmZmVjdHMuIAoKIyMjIEhTUDcwCgpIZWF0IFNob2NrIFByb3RlaW4gNzAgKEhzcDcwKSBpcyBhIG1vbGVjdWxhciBjaGFwZXJvbmUgdGhhdCBwbGF5cyBjcnVjaWFsIHJvbGVzIGluIG1haW50YWluaW5nIGNlbGx1bGFyIHByb3RlaW4gaG9tZW9zdGFzaXMgYW5kIHByb3RlY3RpbmcgY2VsbHMgZnJvbSBzdHJlc3MuIAoKYGBge3IsIGV2YWw9VFJVRX0KCm1vZGVsPC1kZWx0YV9DcV9kZiU+JQogIGZpbHRlcihUYXJnZXQ9PSJIU1A3MCIpJT4lCiAgCiAgYW92KGRlbHRhX0NxIH4gbGlmZS5zdGFnZSAqIGNvbmRpdGlvbmluZy50cmVhdG1lbnQgKiBhY3V0ZS50cmVhdG1lbnQsIGRhdGE9LikKCnN1bW1hcnkobW9kZWwpCgpxcVBsb3QobW9kZWwkcmVzaWR1YWxzKQoKbGV2ZW5lVGVzdChtb2RlbCRyZXNpZHVhbHMgfiBsaWZlLnN0YWdlKmNvbmRpdGlvbmluZy50cmVhdG1lbnQqYWN1dGUudHJlYXRtZW50LCBkYXRhPWRlbHRhX0NxX2RmJT4lZmlsdGVyKFRhcmdldD09IkhTUDcwIikpCgplbW08LWVtbWVhbnMobW9kZWwsIH4gY29uZGl0aW9uaW5nLnRyZWF0bWVudDphY3V0ZS50cmVhdG1lbnQgfCBsaWZlLnN0YWdlKQpwYWlycyhlbW0pCmBgYApTaWduaWZpY2FudCBlZmZlY3Qgb2YgY29uZGl0aW9uaW5nIHggYWN1dGUgdHJlYXRtZW50LiAKCiMjIyBIU1A5MAoKSGVhdCBzaG9jayBwcm90ZWluIDkwIChIc3A5MCkgaXMgYSBtb2xlY3VsYXIgY2hhcGVyb25lIHRoYXQgaGVscHMgcHJvdGVpbnMgZm9sZCwgbWF0dXJlLCBhbmQgcmVtYWluIGFjdGl2ZS4gSHNwOTAgYWxzbyBoZWxwcyByZWd1bGF0ZSBzaWduYWxpbmcgbmV0d29ya3MgYW5kIGlzIGludm9sdmVkIGluIG1hbnkgY2VsbHVsYXIgcHJvY2Vzc2VzLgoKYGBge3IsIGV2YWw9VFJVRX0KbW9kZWw8LWRlbHRhX0NxX2RmJT4lCiAgZmlsdGVyKFRhcmdldD09IkhTUDkwIiklPiUKICAKICBhb3YoZGVsdGFfQ3EgfiBsaWZlLnN0YWdlICogY29uZGl0aW9uaW5nLnRyZWF0bWVudCAqIGFjdXRlLnRyZWF0bWVudCwgZGF0YT0uKQoKc3VtbWFyeShtb2RlbCkKCnFxUGxvdChtb2RlbCRyZXNpZHVhbHMpCgpsZXZlbmVUZXN0KG1vZGVsJHJlc2lkdWFscyB+IGxpZmUuc3RhZ2UqY29uZGl0aW9uaW5nLnRyZWF0bWVudCphY3V0ZS50cmVhdG1lbnQsIGRhdGE9ZGVsdGFfQ3FfZGYlPiVmaWx0ZXIoVGFyZ2V0PT0iSFNQOTAiKSkKCmVtbTwtZW1tZWFucyhtb2RlbCwgfiBjb25kaXRpb25pbmcudHJlYXRtZW50OmFjdXRlLnRyZWF0bWVudCB8IGxpZmUuc3RhZ2UpCnBhaXJzKGVtbSkKYGBgClNpZ25pZmljYW50IGVmZmVjdCBvZiBsaWZlc3RhZ2UgeCBhY3V0ZSB0cmVhdG1lbnQsIGxpZmVzdGFnZSB4IGNvbmRpdGlvbmluZyB0cmVhdG1lbnQsIGFjdXRlIHRyZWF0bWVudCwgYW5kIGxpZmVzdGFnZS4gCgojIyMgY0dBUwoKVGhlIGNHQVMgZ2VuZSBpcyBpbnZvbHZlZCBpbiBzZXZlcmFsIHByb2Nlc3NlcywgaW5jbHVkaW5nIGNlbGx1bGFyIHJlc3BvbnNlIHRvIGV4b2dlbm91cyBkc1JOQSwgcG9zaXRpdmUgcmVndWxhdGlvbiBvZiBpbnRyYWNlbGx1bGFyIHNpZ25hbCB0cmFuc2R1Y3Rpb24sIGFuZCByZWd1bGF0aW9uIG9mIGRlZmVuc2UgcmVzcG9uc2UuCgpgYGB7ciwgZXZhbD1UUlVFfQoKbW9kZWw8LWRlbHRhX0NxX2RmJT4lCiAgZmlsdGVyKFRhcmdldD09ImNHQVMiKSU+JQogIAogIGFvdihkZWx0YV9DcSB+IGxpZmUuc3RhZ2UgKiBjb25kaXRpb25pbmcudHJlYXRtZW50ICogYWN1dGUudHJlYXRtZW50LCBkYXRhPS4pCgpzdW1tYXJ5KG1vZGVsKQoKcXFQbG90KG1vZGVsJHJlc2lkdWFscykKCmxldmVuZVRlc3QobW9kZWwkcmVzaWR1YWxzIH4gbGlmZS5zdGFnZSpjb25kaXRpb25pbmcudHJlYXRtZW50KmFjdXRlLnRyZWF0bWVudCwgZGF0YT1kZWx0YV9DcV9kZiU+JWZpbHRlcihUYXJnZXQ9PSJjR0FTIikpCgplbW08LWVtbWVhbnMobW9kZWwsIH4gY29uZGl0aW9uaW5nLnRyZWF0bWVudDphY3V0ZS50cmVhdG1lbnQgfCBsaWZlLnN0YWdlKQpwYWlycyhlbW0pCmBgYApTaWduaWZpY2FudCBlZmZlY3Qgb2YgbGlmZXN0YWdlIHggYWN1dGUgdHJlYXRtZW50IGFuZCBsaWZlc3RhZ2UuICAKCiMjIyBDaXRyYXRlIHN5bnRoYXNlIAoKQ2l0cmF0ZSBzeW50aGFzZSBpcyBpbXBvcnRhbnQgZm9yIGVuZXJneSBwcm9kdWN0aW9uIGluIHRoZSBUQ0EgY3ljbGUgYW5kIGlzIGxpbmtlZCB0byB0aGUgZWxlY3Ryb24gdHJhbnNwb3J0IGNoYWluLiBJdCBpcyBhbHNvIHVzZWQgYXMgYW4gZW56eW1lIG1hcmtlciBmb3IgaW50YWN0IG1pdG9jaG9uZHJpYS4KCmBgYHtyLCBldmFsPVRSVUV9Cm1vZGVsPC1kZWx0YV9DcV9kZiU+JQogIGZpbHRlcihUYXJnZXQ9PSJjaXRyYXRlIHN5bnRoYXNlIiklPiUKICAKICBhb3YoZGVsdGFfQ3EgfiBsaWZlLnN0YWdlICogY29uZGl0aW9uaW5nLnRyZWF0bWVudCAqIGFjdXRlLnRyZWF0bWVudCwgZGF0YT0uKQoKc3VtbWFyeShtb2RlbCkKCnFxUGxvdChtb2RlbCRyZXNpZHVhbHMpCgpsZXZlbmVUZXN0KG1vZGVsJHJlc2lkdWFscyB+IGxpZmUuc3RhZ2UqY29uZGl0aW9uaW5nLnRyZWF0bWVudCphY3V0ZS50cmVhdG1lbnQsIGRhdGE9ZGVsdGFfQ3FfZGYlPiVmaWx0ZXIoVGFyZ2V0PT0iY2l0cmF0ZSBzeW50aGFzZSIpKQoKZW1tPC1lbW1lYW5zKG1vZGVsLCB+IGNvbmRpdGlvbmluZy50cmVhdG1lbnQ6YWN1dGUudHJlYXRtZW50IHwgbGlmZS5zdGFnZSkKcGFpcnMoZW1tKQpgYGAKU2lnbmlmaWNhbnQgZWZmZWN0IG9mIGFjdXRlIHRyZWF0bWVudCBhbmQgbGlmZXN0YWdlIHggYWN1dGUgdHJlYXRtZW50LiAgCgpBbGwgdGVzdHMgcGFzcyBub3JtYWxpdHkgYW5kIGhvbW9nZW5laXR5IG9mIHZhcmlhbmNlLiBBTk9WQSB0ZXN0cyBhcmUgYXBwcm9wcmlhdGUuIAoKIyMgUGxvdHRpbmcgCgpEaXNwbGF5IHBsb3Qgb2YgYWN1dGUgeCBjb25kaXRpb25pbmcgdHJlYXRtZW50IGZhY2V0ZWQgZm9yIGVhY2ggbGlmZXN0YWdlIGZvciBlYWNoIHRhcmdldC4gIAoKU2hvdyBzYW1wbGUgc2l6ZSBmb3IgZWFjaCBncm91cC4gCmBgYHtyLCBldmFsPVRSVUV9CmRlbHRhX0NxX2RmJT4lCiAgZ3JvdXBfYnkobGlmZS5zdGFnZSwgYWN1dGUudHJlYXRtZW50LCBjb25kaXRpb25pbmcudHJlYXRtZW50KSU+JQogIHN1bW1hcmlzZShuPWxlbmd0aCh1bmlxdWUoU2FtcGxlKSkpCmBgYAoKTm90ZSB0aGF0IHNhbXBsZSBzaXplcyBmb3Igc3BhdCwgc2VlZCwgb3IganV2ZW5pbGVzIHRoYXQgYXJlIDw2IGFyZSBkdWUgdG8gbGFjayBvZiBSTkEgaXNvbGF0ZWQgZnJvbSB0aGUgc2FtcGxlcy4gCgpBZHVsdHMgd2VyZSBhbGwgc2FtcGxlZCBmcm9tIG9uZSBmYW1pbHkgKFBpbmspLiBQcmV2aW91cyBmbG93IGN5dG9tZXRyeSB3YXMgdW5jbGVhciBhcyB0byBkaXBsb2lkIG9yIHRyaXBsb2lkIGNsYXNzaWZpY2F0aW9uLiBXZSBoYXZlIGV4dHJhY3RlZCBETkEgdGhhdCB3ZSBjYW4gdXNlIHRvIHZlcmlmeSBwbG9pZHkuIAoKIyMjIEFUUCBzeW50aGFzZTogTm8gZWZmZWN0cwpgYGB7ciwgZXZhbD1UUlVFfQpwbG90MTwtZGVsdGFfQ3FfZGYlPiUKICBmaWx0ZXIoVGFyZ2V0PT0iQVRQc3ludGhhc2UiKSU+JQogIAogIGdyb3VwX2J5KFRhcmdldCwgbGlmZS5zdGFnZSwgYWN1dGUudHJlYXRtZW50LCBjb25kaXRpb25pbmcudHJlYXRtZW50KSU+JQogIHN1bW1hcmlzZShtZWFuPW1lYW4oZGVsdGFfQ3EsIG5hLnJtPVRSVUUpLCBzZT1zZChkZWx0YV9DcSwgbmEucm09VFJVRSkvc3FydChsZW5ndGgoZGVsdGFfQ3EpKSklPiUKICAKICBnZ3Bsb3QoYWVzKHg9YWN1dGUudHJlYXRtZW50LCB5PW1lYW4sIGNvbG91cj1jb25kaXRpb25pbmcudHJlYXRtZW50KSkrCiAgZmFjZXRfZ3JpZCh+bGlmZS5zdGFnZSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyYXkiLCAib3JhbmdlIikpKwogIGdlb21fcG9pbnQoKSsKICBnZW9tX2xpbmUoYWVzKGdyb3VwPWNvbmRpdGlvbmluZy50cmVhdG1lbnQpKSsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tc2UsIHltYXg9bWVhbitzZSksIHdpZHRoPTAuMSkrCiAgZ2d0aXRsZSgiQVRQIHN5bnRoYXNlIChubyBzaWduLiBlZmZlY3RzKSIpKwogIHlsYWIoIkRlbHRhIENxIikrCiAgeWxpbSgtMC41LDEuNSkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGxpbmV0eXBlPSJkYXNoZWQiKSsKICB0aGVtZV9jbGFzc2ljKCk7cGxvdDEKYGBgCgojIyMgRE5NVDE6IE5vIGVmZmVjdHMKYGBge3IsIGV2YWw9VFJVRX0KcGxvdDI8LWRlbHRhX0NxX2RmJT4lCiAgZmlsdGVyKFRhcmdldD09IkROTVQxIiklPiUKICAKICBncm91cF9ieShUYXJnZXQsIGxpZmUuc3RhZ2UsIGFjdXRlLnRyZWF0bWVudCwgY29uZGl0aW9uaW5nLnRyZWF0bWVudCklPiUKICBzdW1tYXJpc2UobWVhbj1tZWFuKGRlbHRhX0NxLCBuYS5ybT1UUlVFKSwgc2U9c2QoZGVsdGFfQ3EsIG5hLnJtPVRSVUUpL3NxcnQobGVuZ3RoKGRlbHRhX0NxKSkpJT4lCiAgCiAgZ2dwbG90KGFlcyh4PWFjdXRlLnRyZWF0bWVudCwgeT1tZWFuLCBjb2xvdXI9Y29uZGl0aW9uaW5nLnRyZWF0bWVudCkpKwogIGZhY2V0X2dyaWQofmxpZmUuc3RhZ2UpKwogIGdlb21fcG9pbnQoKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jKCJkYXJrZ3JheSIsICJvcmFuZ2UiKSkrCiAgZ2VvbV9saW5lKGFlcyhncm91cD1jb25kaXRpb25pbmcudHJlYXRtZW50KSkrCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLXNlLCB5bWF4PW1lYW4rc2UpLCB3aWR0aD0wLjEpKwogIGdndGl0bGUoIkRNTlQxIChubyBzaWduLiBlZmZlY3RzKSIpKwogIHlsYWIoIkRlbHRhIENxIikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGxpbmV0eXBlPSJkYXNoZWQiKSsKICB5bGltKDAsOSkrCiAgdGhlbWVfY2xhc3NpYygpO3Bsb3QyCmBgYAoKIyMjIEhTUDcwOiBTaWduaWZpY2FudCBlZmZlY3Qgb2YgY29uZGl0aW9uaW5nIHggYWN1dGUgdHJlYXRtZW50LiAKYGBge3IsIGV2YWw9VFJVRX0KcGxvdDM8LWRlbHRhX0NxX2RmJT4lCiAgZmlsdGVyKFRhcmdldD09IkhTUDcwIiklPiUKICAKICBncm91cF9ieShUYXJnZXQsIGxpZmUuc3RhZ2UsIGFjdXRlLnRyZWF0bWVudCwgY29uZGl0aW9uaW5nLnRyZWF0bWVudCklPiUKICBzdW1tYXJpc2UobWVhbj1tZWFuKGRlbHRhX0NxLCBuYS5ybT1UUlVFKSwgc2U9c2QoZGVsdGFfQ3EsIG5hLnJtPVRSVUUpL3NxcnQobGVuZ3RoKGRlbHRhX0NxKSkpJT4lCiAgCiAgZ2dwbG90KGFlcyh4PWFjdXRlLnRyZWF0bWVudCwgeT1tZWFuLCBjb2xvdXI9Y29uZGl0aW9uaW5nLnRyZWF0bWVudCkpKwogIGZhY2V0X2dyaWQofmxpZmUuc3RhZ2UpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWMoImRhcmtncmF5IiwgIm9yYW5nZSIpKSsKICBnZW9tX3BvaW50KCkrCiAgZ2VvbV9saW5lKGFlcyhncm91cD1jb25kaXRpb25pbmcudHJlYXRtZW50KSkrCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLXNlLCB5bWF4PW1lYW4rc2UpLCB3aWR0aD0wLjEpKwogIGdndGl0bGUoIkhTUDcwICAoc2lnbi4gY29uZGl0aW9uaW5nIHggYWN1dGUgdHJlYXRtZW50KSIpKwogIHlsYWIoIkRlbHRhIENxIikrCiAgeWxpbSgwLDgpKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBsaW5ldHlwZT0iZGFzaGVkIikrCiAgdGhlbWVfY2xhc3NpYygpO3Bsb3QzCgpwbG90M2E8LWRlbHRhX0NxX2RmJT4lCiAgZmlsdGVyKFRhcmdldD09IkhTUDcwIiklPiUKICAKICBncm91cF9ieShUYXJnZXQsIGFjdXRlLnRyZWF0bWVudCwgY29uZGl0aW9uaW5nLnRyZWF0bWVudCklPiUKICBzdW1tYXJpc2UobWVhbj1tZWFuKGRlbHRhX0NxLCBuYS5ybT1UUlVFKSwgc2U9c2QoZGVsdGFfQ3EsIG5hLnJtPVRSVUUpL3NxcnQobGVuZ3RoKGRlbHRhX0NxKSkpJT4lCiAgCiAgZ2dwbG90KGFlcyh4PWFjdXRlLnRyZWF0bWVudCwgeT1tZWFuLCBjb2xvdXI9Y29uZGl0aW9uaW5nLnRyZWF0bWVudCkpKwogIGdlb21fcG9pbnQoKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jKCJkYXJrZ3JheSIsICJvcmFuZ2UiKSkrCiAgZ2VvbV9saW5lKGFlcyhncm91cD1jb25kaXRpb25pbmcudHJlYXRtZW50KSkrCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLXNlLCB5bWF4PW1lYW4rc2UpLCB3aWR0aD0wLjEpKwogIGdndGl0bGUoIkhTUDcwICAoc2lnbi4gY29uZGl0aW9uaW5nIHggYWN1dGUgdHJlYXRtZW50KSIpKwogIHlsYWIoIkRlbHRhIENxIikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGxpbmV0eXBlPSJkYXNoZWQiKSsKICB5bGltKDAsOCkrCiAgdGhlbWVfY2xhc3NpYygpO3Bsb3QzYQpgYGAKCiMjIyBIU1A5MDogU2lnbmlmaWNhbnQgZWZmZWN0IG9mIGxpZmVzdGFnZSB4IGFjdXRlIHRyZWF0bWVudCwgbGlmZXN0YWdlIHggY29uZGl0aW9uaW5nIHRyZWF0bWVudCwgYWN1dGUgdHJlYXRtZW50LCBhbmQgbGlmZXN0YWdlLiAKYGBge3IsIGV2YWw9VFJVRX0KcGxvdDQ8LWRlbHRhX0NxX2RmJT4lCiAgZmlsdGVyKFRhcmdldD09IkhTUDkwIiklPiUKICAKICBncm91cF9ieShUYXJnZXQsIGxpZmUuc3RhZ2UsIGFjdXRlLnRyZWF0bWVudCwgY29uZGl0aW9uaW5nLnRyZWF0bWVudCklPiUKICBzdW1tYXJpc2UobWVhbj1tZWFuKGRlbHRhX0NxLCBuYS5ybT1UUlVFKSwgc2U9c2QoZGVsdGFfQ3EsIG5hLnJtPVRSVUUpL3NxcnQobGVuZ3RoKGRlbHRhX0NxKSkpJT4lCiAgCiAgZ2dwbG90KGFlcyh4PWFjdXRlLnRyZWF0bWVudCwgeT1tZWFuLCBjb2xvdXI9Y29uZGl0aW9uaW5nLnRyZWF0bWVudCkpKwogIGZhY2V0X2dyaWQofmxpZmUuc3RhZ2UpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWMoImRhcmtncmF5IiwgIm9yYW5nZSIpKSsKICBnZW9tX3BvaW50KCkrCiAgZ2VvbV9saW5lKGFlcyhncm91cD1jb25kaXRpb25pbmcudHJlYXRtZW50KSkrCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLXNlLCB5bWF4PW1lYW4rc2UpLCB3aWR0aD0wLjEpKwogIGdndGl0bGUoIkhTUDkwICAoc2lnbi4gbGlmZXN0YWdlIHggYWN1dGUgJiBsaWZlc3RhZ2UgeCBjb25kaXRpb25pbmcgdHJlYXRtZW50KSIpKwogIHlsYWIoIkRlbHRhIENxIikrCiAgeWxpbSgtMiwyLjUpKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBsaW5ldHlwZT0iZGFzaGVkIikrCiAgdGhlbWVfY2xhc3NpYygpO3Bsb3Q0CmBgYAoKIyMjIGNHQVM6IFNpZ25pZmljYW50IGVmZmVjdCBvZiBsaWZlc3RhZ2UgeCBhY3V0ZSB0cmVhdG1lbnQgYW5kIGxpZmVzdGFnZS4gIApgYGB7ciwgZXZhbD1UUlVFfQpwbG90NTwtZGVsdGFfQ3FfZGYlPiUKICBmaWx0ZXIoVGFyZ2V0PT0iY0dBUyIpJT4lCiAgCiAgZ3JvdXBfYnkoVGFyZ2V0LCBsaWZlLnN0YWdlLCBhY3V0ZS50cmVhdG1lbnQsIGNvbmRpdGlvbmluZy50cmVhdG1lbnQpJT4lCiAgc3VtbWFyaXNlKG1lYW49bWVhbihkZWx0YV9DcSwgbmEucm09VFJVRSksIHNlPXNkKGRlbHRhX0NxLCBuYS5ybT1UUlVFKS9zcXJ0KGxlbmd0aChkZWx0YV9DcSkpKSU+JQogIAogIGdncGxvdChhZXMoeD1hY3V0ZS50cmVhdG1lbnQsIHk9bWVhbiwgY29sb3VyPWNvbmRpdGlvbmluZy50cmVhdG1lbnQpKSsKICBmYWNldF9ncmlkKH5saWZlLnN0YWdlKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jKCJkYXJrZ3JheSIsICJvcmFuZ2UiKSkrCiAgZ2VvbV9wb2ludCgpKwogIGdlb21fbGluZShhZXMoZ3JvdXA9Y29uZGl0aW9uaW5nLnRyZWF0bWVudCkpKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bWVhbi1zZSwgeW1heD1tZWFuK3NlKSwgd2lkdGg9MC4xKSsKICBnZ3RpdGxlKCJjR0FTICAoc2lnbi4gbGlmZXN0YWdlIHggYWN1dGUgdHJlYXRtZW50KSIpKwogIHlsYWIoIkRlbHRhIENxIikrCiAgeWxpbSgyLDgpKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBsaW5ldHlwZT0iZGFzaGVkIikrCiAgdGhlbWVfY2xhc3NpYygpO3Bsb3Q1CmBgYAoKIyMjIENpdHJhdGUgc3ludGhhc2U6IFNpZ25pZmljYW50IGVmZmVjdCBvZiBhY3V0ZSB0cmVhdG1lbnQgYW5kIGxpZmVzdGFnZSB4IGFjdXRlIHRyZWF0bWVudC4gIAoKYGBge3IsIGV2YWw9VFJVRX0KcGxvdDY8LWRlbHRhX0NxX2RmJT4lCiAgZmlsdGVyKFRhcmdldD09ImNpdHJhdGUgc3ludGhhc2UiKSU+JQogIAogIGdyb3VwX2J5KFRhcmdldCwgbGlmZS5zdGFnZSwgYWN1dGUudHJlYXRtZW50LCBjb25kaXRpb25pbmcudHJlYXRtZW50KSU+JQogIHN1bW1hcmlzZShtZWFuPW1lYW4oZGVsdGFfQ3EsIG5hLnJtPVRSVUUpLCBzZT1zZChkZWx0YV9DcSwgbmEucm09VFJVRSkvc3FydChsZW5ndGgoZGVsdGFfQ3EpKSklPiUKICAKICBnZ3Bsb3QoYWVzKHg9YWN1dGUudHJlYXRtZW50LCB5PW1lYW4sIGNvbG91cj1jb25kaXRpb25pbmcudHJlYXRtZW50KSkrCiAgZmFjZXRfZ3JpZCh+bGlmZS5zdGFnZSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyYXkiLCAib3JhbmdlIikpKwogIGdlb21fcG9pbnQoKSsKICBnZW9tX2xpbmUoYWVzKGdyb3VwPWNvbmRpdGlvbmluZy50cmVhdG1lbnQpKSsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tc2UsIHltYXg9bWVhbitzZSksIHdpZHRoPTAuMSkrCiAgZ2d0aXRsZSgiY0dBUyAgKHNpZ24uIGxpZmVzdGFnZSB4IGFjdXRlIHRyZWF0bWVudCkiKSsKICB5bGFiKCJEZWx0YSBDcSIpKwogIHlsaW0oLTIsMykrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGxpbmV0eXBlPSJkYXNoZWQiKSsKICB0aGVtZV9jbGFzc2ljKCk7cGxvdDYKYGBgCgojIyBDb25jbHVzaW9ucyAKCiMjIyBFZmZlY3RzIG9mIGNvbmRpdGlvbmluZyBvbiBhY3V0ZSBzdHJlc3MgcmVzcG9uc2UgICAKCi0gSFNQNzAgYW5kIDkwIGdlbmVzIGFyZSBhZmZlY3RlZCBieSBjb25kaXRpb25pbmcuIAotIEhTUDkwIGhhcyBzaWduaWZpY2FudGx5IGhpZ2hlciBleHByZXNzaW9uIGluIHRyZWF0ZWQgYWR1bHRzIHRoYW4gY29udHJvbCBhZHVsdHMgYXQgZWxldmF0ZWQgdGVtcGVyYXR1cmUuIE5vIG90aGVyIGxpZmVzdGFnZXMgaGF2ZSBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBpbiBleHByZXNzaW9uIGJldHdlZW4gY29uZGl0aW9uaW5nIHRyZWF0bWVudHMgYXQgaGlnaCB0ZW1wZXJhdHVyZS4gIAotIEhTUDcwIGhhcyBzaWduaWZpY2FudGx5IGxvd2VyIGV4cHJlc3Npb24gaW4gdHJlYXRlZCBzcGF0IHRoYW4gY29udHJvbCBzcGF0IGF0IGVsZXZhdGVkIHRlbXBlcmF0dXJlLiBObyBvdGhlciBsaWZlc3RhZ2VzIGhhdmUgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgYmV0d2VlbiBjb25kaXRpb25pbmcgdHJlYXRtZW50cyBhdCBoaWdoIHRlbXBlcmF0dXJlLiAKCiMjIyBFZmZlY3RzIG9mIGFjdXRlIHN0cmVzcyBhbmQgbGlmZXN0YWdlIAoKLSBBY3Jvc3MgbGlmZXN0YWdlcyAoZXhjZXB0IGZvciBqdXZlbmlsZXMpIEhTUDkwIGRlY3JlYXNlcyBpbiBleHByZXNzaW9uIHVuZGVyIGVsZXZhdGVkIHRlbXBlcmF0dXJlLiAKLSBFeHByZXNzaW9uIG9mIGNHQVMgaW5jcmVhc2VzIG1vc3QgZHJhbWF0aWNhbGx5IGluIHNlZWQgdW5kZXIgZWxldmF0ZWQgdGVtcGVyYXR1cmUuIAotIEFUUCBzeW50aGFzZSBhbmQgRE1OVDEgYXJlIG5vdCBhZmZlY3RlZCBieSBlbGV2YXRlZCB0ZW1wZXJhdHVyZS4gCi0gQ2l0cmF0ZSBzeW50aGFzZSBpbmNyZWFzZXMgaW4gZXhwcmVzc2lvbiBpbiBzZWVkIGFuZCBzcGF0IHVuZGVyIGVsZXZhdGVkIHRlbXBlcmF0dXJlLCBidXQgZG9lcyBub3QgY2hhbmdlIGluIGFkdWx0IG9yIGp1dmVuaWxlIHN0YWdlcy4gCi0gRWZmZWN0cyBvZiBhY3V0ZSB0cmVhdG1lbnQgYW5kIGxpZmUgc3RhZ2UgYXJlIGp1c3QgYmFyZWx5IG5vdCBzaWduaWZpY2FudCBmb3IgQVRQc3ludGhhc2UgYW5kIERNTlQxLiBJdCBpcyBwYXJ0aWN1bGFybHkgaW50ZXJlc3RpbmcgdG8gc2VlIHRoZSB0cmVuZCBmb3IgaGlnaGVyIERNTlQxIGV4cHJlc3Npb24gaW4gc3BhdCBhdCBhbWJpZW50IHRlbXBlcmF0dXJlLiBUaGVyZSBpcyBhbHNvIGEgdHJlbmQgZm9yIGxvd2VyIGV4cHJlc3Npb24gb2YgQVRQc3ludGhhc2UgaW4gc2VlZCBhdCBoaWdoIHRlbXBlcmF0dXJlLCBidXQgbm90IHRlY2huaWNhbGx5IHNpZ25pZmljYW50LiAgCgoKCg==